/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. solidity is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with solidity. If not, see . */ // SPDX-License-Identifier: GPL-3.0 #pragma once #include #include #include #include #include #include #include namespace solidity::util { /** * A literal of a (potentially negated) boolean variable or an inactive constraint. */ struct Literal { enum { PositiveVariable, NegativeVariable, Constraint } kind; // Either points to a boolean variable or to a constraint. size_t index{0}; }; /** * A clause is a disjunction of literals. */ struct Clause { std::vector literals; }; struct State { bool infeasible = false; std::map variables; std::vector isBooleanVariable; // Potential constraints, referenced through clauses std::map constraints; // Unconditional bounds on variables std::map>, 2>> bounds; std::vector clauses; }; struct DPLL { /// Try to simplify the set of clauses without branching. /// @returns false if the set of clauses is unsatisfiable (without considering the constraints). std::pair> simplify(); size_t findUnassignedVariable() const; bool setVariable(size_t _index, bool _value); /// Sets variables and removes clauses or literals from clauses. /// @returns false if the clauses are unsatisfiable. bool setVariables(std::map const& _assignments, bool _removeSingleConstraintClauses = false); std::vector clauses; std::vector constraints; }; /** * Component that satisfies the SMT SolverInterface and uses an LP solver plus the DPLL * algorithm internally. * It uses a rational relaxation of the integer program and thus will not be able to answer * "satisfiable", but its answers are still correct. * * TODO are integers always non-negative? * * Integers are unbounded. */ class BooleanLPSolver: public smtutil::SolverInterface { public: void reset() override; void push() override; void pop() override; void declareVariable(std::string const& _name, smtutil::SortPointer const& _sort) override; void addAssertion(smtutil::Expression const& _expr) override; std::pair> check(std::vector const& _expressionsToEvaluate) override; std::pair>> check(); std::string toString() const; private: using rational = boost::rational; smtutil::Expression declareInternalBoolean(); void declareVariable(std::string const& _name, bool _boolean); std::optional parseLiteral(smtutil::Expression const& _expr); Literal negate(Literal const& _lit); Literal parseLiteralOrReturnEqualBoolean(smtutil::Expression const& _expr); /// Parses the expression and expects a linear sum of variables. /// Returns a vector with the first element being the constant and the /// other elements the factors for the respective variables. /// If the expression cannot be properly parsed or is not linear, /// returns an empty vector. std::optional> parseLinearSum(smtutil::Expression const& _expression) const; std::optional> parseProduct(smtutil::Expression const& _expression) const; std::optional> parseFactor(smtutil::Expression const& _expression) const; bool tryAddDirectBounds(Constraint const& _constraint); void addUpperBound(size_t _index, rational _value); void addLowerBound(size_t _index, rational _value); size_t addConstraint(Constraint _constraint); void addBooleanEquality(Literal const& _left, smtutil::Expression const& _right); std::pair> runDPLL(SolvingState& _solvingState, DPLL _dpll); std::string toString(DPLL const& _dpll) const; std::string toString(std::vector>, 2>> const& _bounds) const; std::string toString(Clause const& _clause) const; Constraint const& constraint(size_t _index) const; std::string variableName(size_t _index) const; bool isBooleanVariable(std::string const& _name) const; bool isBooleanVariable(size_t _index) const; size_t m_constraintCounter = 0; size_t m_internalVariableCounter = 0; /// Stack of state, to allow for push()/pop(). std::vector m_state{{State{}}}; LPSolver m_lpSolver{false}; }; }