Package solver.constraints.nary.cnf

Source Code of solver.constraints.nary.cnf.SatSolver$Clause

/**
*  Copyright (c) 1999-2014, Ecole des Mines de Nantes
*  All rights reserved.
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions are met:
*
*      * Redistributions of source code must retain the above copyright
*        notice, this list of conditions and the following disclaimer.
*      * Redistributions in binary form must reproduce the above copyright
*        notice, this list of conditions and the following disclaimer in the
*        documentation and/or other materials provided with the distribution.
*      * Neither the name of the Ecole des Mines de Nantes nor the
*        names of its contributors may be used to endorse or promote products
*        derived from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
*  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
*  DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
*  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
*  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package solver.constraints.nary.cnf;

import gnu.trove.list.TIntList;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.map.hash.TIntObjectHashMap;

import java.util.ArrayList;

/**
* A MiniSat solver.
* <p/>
* (or-tools, booleans.cc, ty L. Perron).
* <br/>
*
* @author Charles Prud'homme
* @since 12/07/13
*/
public class SatSolver {


    /**
     * static const Literal kUndefinedLiteral = Literal(-2);
     */
    static final int kUndefinedLiteral = -2;

    /**
     * static const Literal kErrorLiteral = Literal(-1);
     */
    static final int kErrorLiteral = -1;

    // If false, the constraints are already unsatisfiable. No part of
    // the solver state may be used!
    boolean ok_;
    // List of problem addClauses.
    ArrayList<Clause> clauses;
    // 'watches_[lit]' is a list of constraints watching 'lit'(will go
    // there if literal becomes true).
    TIntObjectHashMap<ArrayList<Watcher>> watches_;
    // implies_[lit] is a list of literals to set to true if 'lit' becomes true.
    TIntObjectHashMap<TIntList> implies_;
    // The current assignments.
    TIntObjectHashMap<Boolean> assignment_;
    // Assignment stack; stores all assigments made in the order they
    // were made.
    TIntList trail_;
    // Separator indices for different decision levels in 'trail_'.
    TIntList trail_markers_;
    // Head of queue(as index into the trail_.
    int qhead_;
    // Number of variables
    int num_vars_;

    TIntArrayList temporary_add_vector_;
    TIntArrayList touched_variables_;


    public SatSolver() {
        this.ok_ = true;
        this.qhead_ = 0;
        num_vars_ = 0;
        this.clauses = new ArrayList<Clause>();
        this.watches_ = new TIntObjectHashMap<ArrayList<Watcher>>();
        this.implies_ = new TIntObjectHashMap<TIntList>();
        this.assignment_ = new TIntObjectHashMap<Boolean>();
        this.trail_ = new TIntArrayList();
        this.trail_markers_ = new TIntArrayList();
        this.temporary_add_vector_ = new TIntArrayList();
        this.touched_variables_ = new TIntArrayList();
    }

    // Add a new variable.
    public int newVariable() {
        int v = incrementVariableCounter();
//            watches_.resize(2 * v + 2);
//        implies_.resize(2 * v.value() + 2);
        assignment_.put(v, Boolean.kUndefined);
        return v;
    }


    // Add a clause to the solver.
    boolean addClause(TIntList ps) {
        assert 0 == trailMarker();
        if (!ok_) return false;

        // Check if clause is satisfied and remove false/duplicated literals:
        ps.sort();
        int lit = kUndefinedLiteral;
        int j = 0;
        for (int i = 0; i < ps.size(); i++) {
            if (valueLit(ps.get(i)) == Boolean.kTrue || ps.get(i) == negated(lit)) {
                return true;
            } else if (valueLit(ps.get(i)) != Boolean.kFalse && ps.get(i) != lit) {
                lit = ps.get(i);
                ps.set(j++, lit);
            }
        }
        if (j < ps.size() - 1) {
            ps.remove(j + 1, ps.size() - j - 1);
        }


        switch (ps.size()) {
            case 0:
            return (ok_ = false);
            case 1:
            uncheckedEnqueue(ps.get(0));
            return (ok_ = propagate());
            case 2:
                int l0 = ps.get(0);
                int l1 = ps.get(1);
                TIntList i0 = implies_.get(negated(l0));
                if (i0 == null) {
                    i0 = new TIntArrayList();
                    implies_.put(negated(l0), i0);
                }
                i0.add(l1);

                TIntList i1 = implies_.get(negated(l1));
                if (i1 == null) {
                    i1 = new TIntArrayList();
                    implies_.put(negated(l1), i1);
                }
                i1.add(l0);
                break;
            default:
            Clause cr = new Clause(ps.toArray());
            clauses.add(cr);
            attachClause(cr);
                break;

        }
        return true;
    }

    // Add the empty clause, making the solver contradictory.
    boolean addEmptyClause() {
        temporary_add_vector_.clear();
        return addClause(temporary_add_vector_);
    }

    // Add a unit clause to the solver.
    boolean addClause(int l) {
        temporary_add_vector_.clear();
        temporary_add_vector_.add(l);
        return addClause(temporary_add_vector_);
    }

    // Add a binary clause to the solver.
    boolean addClause(int p, int q) {
        temporary_add_vector_.clear();
        temporary_add_vector_.add(p);
        temporary_add_vector_.add(q);
        return addClause(temporary_add_vector_);
    }

    // Add a ternary clause to the solver.
    boolean addClause(int p, int q, int r) {
        temporary_add_vector_.clear();
        temporary_add_vector_.add(p);
        temporary_add_vector_.add(q);
        temporary_add_vector_.add(r);
        return addClause(temporary_add_vector_);
    }

    // Incremental propagation.
    boolean initPropagator() {
        touched_variables_.clear();
        return !ok_;
    }

    // Backtrack until a certain level.
    void cancelUntil(int level) {
        if (trailMarker() > level) {
            for (int c = trail_.size() - 1; c >= trail_markers_.get(level); c--) {
                int x = var(trail_.get(c));
                assignment_.put(x, Boolean.kUndefined);
            }
            qhead_ = trail_markers_.get(level);
            trail_.remove(trail_markers_.get(level), trail_.size() - trail_markers_.get(level));
            trail_markers_.remove(level, trail_markers_.size() - level);
        }
    }

    // Gives the current decisionlevel.
    public int trailMarker() {
        return trail_markers_.size();
    }

    // The current value of a variable.
    Boolean valueVar(int x) {
        return assignment_.get(x);
    }

    // The current value of a literal.
    Boolean valueLit(int l) {
        Boolean b = assignment_.get(var(l));
        return b == Boolean.kUndefined ? Boolean.kUndefined : xor(b, sign(l));
    }

    // The current number of original clauses.
    int nClauses() {
        return clauses.size();
    }

    // Propagates one literal, returns true if successful, false in case
    // of failure.
    boolean propagateOneLiteral(int lit) {
        assert ok_;
        touched_variables_.clear();
        if (!propagate()) {
            return false;
        }
        if (valueLit(lit) == Boolean.kTrue) {
            // Dummy decision level:
            pushTrailMarker();
            return true;
        } else if (valueLit(lit) == Boolean.kFalse) {
            return false;
        }
        pushTrailMarker();
        // Unchecked enqueue
        assert valueLit(lit) == Boolean.kUndefined;
        assignment_.put(var(lit), makeBoolean(!sign(lit)));
        trail_.add(lit);
        return propagate();
    }


    private int incrementVariableCounter() {
        return num_vars_++;
    }

    // Begins a new decision level.
    void pushTrailMarker() {
        trail_markers_.add(trail_.size());
    }

    // Enqueue a literal. Assumes value of literal is undefined.
    void uncheckedEnqueue(int l) {
        assert valueLit(l) == Boolean.kUndefined;
        if (assignment_.get(var(l)) == Boolean.kUndefined) {
            touched_variables_.add(l);
        }
        assignment_.put(var(l), sign(l) ? Boolean.kFalse : Boolean.kTrue);
        trail_.add(l);
    }

    // Test if fact 'p' contradicts current state, Enqueue otherwise.
    boolean enqueue(int l) {
        if (valueLit(l) != Boolean.kUndefined) {
            return valueLit(l) != Boolean.kFalse;
        } else {
            uncheckedEnqueue(l);
            return true;
        }
    }

    // Attach a clause to watcher lists.
    void attachClause(Clause cr) {
        Clause c = cr;
        assert c.size() > 1;
        ArrayList<Watcher> l0 = watches_.get(negated(c._g(0)));
        if (l0 == null) {
            l0 = new ArrayList<Watcher>();
            watches_.put(negated(c._g(0)), l0);
        }
        ArrayList<Watcher> l1 = watches_.get(negated(c._g(1)));
        if (l1 == null) {
            l1 = new ArrayList<Watcher>();
            watches_.put(negated(c._g(1)), l1);
        }
        l0.add(new Watcher(cr, c._g(1)));
        l1.add(new Watcher(cr, c._g(0)));
    }

    // Perform unit propagation. returns true upon success.
    boolean propagate() {
        boolean result = true;
        while (qhead_ < trail_.size()) {
            int p = trail_.get(qhead_++);
            // Propagate the implies first.
            TIntList to_add = implies_.get(p);
            if (to_add != null) {
                for (int i = 0; i < to_add.size(); ++i) {
                    if (!enqueue(to_add.get(i))) {
                        return false;
                    }
                }
            }

            // 'p' is enqueued fact to propagate.
            ArrayList<Watcher> ws = watches_.get(p);

            int i = 0;
            int j = 0;
            while (ws != null && i < ws.size()) {
                // Try to avoid inspecting the clause:
                int blocker = ws.get(i).blocker;
                if (valueLit(blocker) == Boolean.kTrue) {
                    ws.set(j++, ws.get(i++));
                    continue;
                }

                // Make sure the false literal is data[1]:
                Clause cr = ws.get(i).clause;
                Clause c = cr;
                final int false_lit = negated(p);
                if (c._g(0) == false_lit) {
                    c._s(0, c._g(1));
                    c._s(1, false_lit);
                }
                assert (c._g(1) == false_lit);
                i++;

                // If 0th watch is true, then clause is already satisfied.
                final int first = c._g(0);
                Watcher w = new Watcher(cr, first);
                if (first != blocker && valueLit(first) == Boolean.kTrue) {
                    ws.set(j++, w);
                    continue;
                }

                // Look for new watch:
                boolean cont = false;
                for (int k = 2; k < c.size(); k++) {
                    if (valueLit(c._g(k)) != Boolean.kFalse) {
                        c._s(1, c._g(k));
                        c._s(k, false_lit);
                        ArrayList<Watcher> lw = watches_.get(negated(c._g(1)));
                        if (lw == null) {
                            lw = new ArrayList<Watcher>();
                            watches_.put(negated(c._g(1)), lw);
                        }
                        lw.add(w);
                        cont = true;
                        break;
                    }
                }

                // Did not find watch -- clause is unit under assignment:
                if (!cont) {
                    ws.set(j++, w);
                    if (valueLit(first) == Boolean.kFalse) {
                        result = false;
                        qhead_ = trail_.size();
                        // Copy the remaining watches_:
                        while (i < ws.size()) {
                            ws.set(j++, ws.get(i++));
                        }
                    } else {
                        uncheckedEnqueue(first);
                    }
                }
            }
            if (ws != null) {
                for (int k = ws.size() - 1; k >= j; k--) {
                    ws.remove(k);
                }
            }
        }
        return result;
    }


    /**
     * inline Literal MakeLiteral(Variable var, bool sign) {
     * return Literal(2 * var.value() + static_cast<int>(sign));
     * int(true) is always 1. And int(false) is always 0
     * }
     */
    protected static int makeLiteral(int var, boolean sign) {
        return (2 * var + (sign ? 1 : 0));
    }

    /**
     * inline Literal Negated(Literal p) { return Literal(p.value() ^ 1); }
     */
    public static int negated(int l) {
        return (l ^ 1);
    }


    /**
     * inline bool Sign(Literal p) { return p.value() & 1; }
     * int(true) is always 1. And int(false) is always 0
     */
    protected static boolean sign(int l) {
        return (l & 1) != 0;
    }

    /**
     * inline Variable Var(Literal p) { return Variable(p.value() >> 1); }
     */
    protected static int var(int l) {
        return (l >> 1);
    }

    /**
     * inline Boolean MakeBoolean(bool x) { return Boolean(!x); }
     */
    protected static Boolean makeBoolean(boolean b) {
        return (b ? Boolean.kTrue : Boolean.kFalse);
    }

    /**
     * inline Boolean Xor(Boolean a, bool b) {
     * return Boolean((uint8)(a.value() ^ (uint8) b));
     * }
     */
    protected static Boolean xor(Boolean a, boolean b) {
        return Boolean.make((byte) (a.value() ^ (b ? 1 : 0)));
    }


    /**
     * Clause -- a simple class for representing a clause
     * <br/>
     *
     * @author Charles Prud'homme, Laurent Perron
     * @since 12/07/13
     */
    class Clause {
        private int[] literals_;

        public Clause(int[] ps) {
            literals_ = ps.clone();
        }

        int size() {
            return literals_.length;
        }

        int _g(int i) {
            return literals_[i];
        }

        int _s(int pos, int l) {
            return literals_[pos] = l;
        }
    }

    /**
     * // A watcher represent a clause attached to a literal.
     * <br/>
     * (or-tools, booleans.cc, ty L. Perron).
     *
     * @author Charles Prud'homme
     * @since 12/07/13
     */
    class Watcher {

        Clause clause;
        int blocker;

        public Watcher() {
            blocker = kUndefinedLiteral;
        }

        public Watcher(final Clause cr, int l) {
            this.clause = cr;
            this.blocker = l;
        }
    }

    /**
     * <br/>
     * (or-tools, booleans.cc, ty L. Perron).
     *
     * @author Charles Prud'homme, Laurent Perron
     * @since 12/07/13
     */
    static enum Boolean {

        kTrue((byte) 0),
        kFalse((byte) 1),
        kUndefined((byte) 2);


        byte value;

        Boolean(byte value) {
            this.value = value;
        }

        public byte value() {
            return value;
        }

        public static Boolean make(byte b) {
            if (b == 0) return kTrue;
            else if (b == 1) return kFalse;
            else return kUndefined;
        }

    }

}
TOP

Related Classes of solver.constraints.nary.cnf.SatSolver$Clause

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.