LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/arith/linear - simplex.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 128 191 67.0 %
Date: 2026-06-14 10:35:19 Functions: 10 20 50.0 %
Branches: 81 182 44.5 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * This file is part of the cvc5 project.
       3                 :            :  *
       4                 :            :  * Copyright (c) 2009-2026 by the authors listed in the file AUTHORS
       5                 :            :  * in the top-level source directory and their institutional affiliations.
       6                 :            :  * All rights reserved.  See the file COPYING in the top-level source
       7                 :            :  * directory for licensing information.
       8                 :            :  * ****************************************************************************
       9                 :            :  *
      10                 :            :  * This is an implementation of the Simplex Module for the Simplex for
      11                 :            :  * DPLL(T) decision procedure.
      12                 :            :  */
      13                 :            : 
      14                 :            : #include "theory/arith/linear/simplex.h"
      15                 :            : 
      16                 :            : #include "base/output.h"
      17                 :            : #include "options/arith_options.h"
      18                 :            : #include "options/smt_options.h"
      19                 :            : #include "smt/env.h"
      20                 :            : #include "theory/arith/linear/constraint.h"
      21                 :            : #include "theory/arith/linear/error_set.h"
      22                 :            : #include "theory/arith/linear/linear_equality.h"
      23                 :            : #include "theory/arith/linear/tableau.h"
      24                 :            : #include "util/statistics_value.h"
      25                 :            : 
      26                 :            : using namespace std;
      27                 :            : 
      28                 :            : namespace cvc5::internal {
      29                 :            : namespace theory {
      30                 :            : namespace arith::linear {
      31                 :            : 
      32                 :     205084 : SimplexDecisionProcedure::SimplexDecisionProcedure(
      33                 :            :     Env& env,
      34                 :            :     LinearEqualityModule& linEq,
      35                 :            :     ErrorSet& errors,
      36                 :            :     RaiseConflict conflictChannel,
      37                 :     205084 :     TempVarMalloc tvmalloc)
      38                 :            :     : EnvObj(env),
      39                 :     205084 :       d_pivots(0),
      40                 :     205084 :       d_conflictVariables(),
      41                 :     205084 :       d_linEq(linEq),
      42                 :     205084 :       d_variables(d_linEq.getVariables()),
      43                 :     205084 :       d_tableau(d_linEq.getTableau()),
      44                 :     205084 :       d_errorSet(errors),
      45                 :     205084 :       d_numVariables(0),
      46                 :     205084 :       d_conflictChannel(conflictChannel),
      47                 :     205084 :       d_conflictBuilder(nullptr),
      48                 :     205084 :       d_arithVarMalloc(tvmalloc),
      49                 :     205084 :       d_errorSize(0),
      50                 :     205084 :       d_zero(0),
      51                 :     205084 :       d_posOne(1),
      52                 :     410168 :       d_negOne(-1)
      53                 :            : {
      54                 :     205084 :   d_heuristicRule = options().arith.arithErrorSelectionRule;
      55                 :     205084 :   d_errorSet.setSelectionRule(d_heuristicRule);
      56                 :     205084 :   d_conflictBuilder = new FarkasConflictBuilder(options().smt.produceProofs);
      57                 :     205084 : }
      58                 :            : 
      59                 :     814768 : SimplexDecisionProcedure::~SimplexDecisionProcedure()
      60                 :            : {
      61         [ +  - ]:     203692 :   delete d_conflictBuilder;
      62                 :     203692 : }
      63                 :            : 
      64                 :    1770592 : bool SimplexDecisionProcedure::standardProcessSignals(TimerStat& timer,
      65                 :            :                                                       IntStat& conflicts)
      66                 :            : {
      67                 :    1770592 :   TimerStat::CodeTimer codeTimer(timer);
      68 [ -  + ][ -  + ]:    1770592 :   Assert(d_conflictVariables.empty());
                 [ -  - ]
      69                 :            : 
      70         [ +  + ]:   15156848 :   while (d_errorSet.moreSignals())
      71                 :            :   {
      72                 :   13386256 :     ArithVar curr = d_errorSet.topSignal();
      73 [ +  + ][ +  + ]:   13386256 :     if (d_tableau.isBasic(curr) && !d_variables.assignmentIsConsistent(curr))
                 [ +  + ]
      74                 :            :     {
      75 [ -  + ][ -  + ]:    1074072 :       Assert(d_linEq.basicIsTracked(curr));
                 [ -  - ]
      76                 :            : 
      77 [ +  + ][ +  + ]:    1074072 :       if (!d_conflictVariables.isMember(curr) && checkBasicForConflict(curr))
                 [ +  + ]
      78                 :            :       {
      79         [ +  - ]:     204404 :         Trace("recentlyViolated")
      80                 :          0 :             << "It worked? " << conflicts.get() << " " << curr << " "
      81                 :     102202 :             << checkBasicForConflict(curr) << endl;
      82                 :     102202 :         reportConflict(curr);
      83                 :     102202 :         ++conflicts;
      84                 :            :       }
      85                 :            :     }
      86                 :            :     // Pop signal afterwards in case d_linEq.trackVariable(curr);
      87                 :            :     // is needed for for the ErrorSet
      88                 :   13386256 :     d_errorSet.popSignal();
      89                 :            :   }
      90                 :    1770592 :   d_errorSize = d_errorSet.errorSize();
      91                 :            : 
      92 [ -  + ][ -  + ]:    1770592 :   Assert(d_errorSet.noSignals());
                 [ -  - ]
      93                 :    3541184 :   return !d_conflictVariables.empty();
      94                 :    1770592 : }
      95                 :            : 
      96                 :            : /** Reports a conflict to on the output channel. */
      97                 :     103262 : void SimplexDecisionProcedure::reportConflict(ArithVar basic)
      98                 :            : {
      99 [ -  + ][ -  + ]:     103262 :   Assert(!d_conflictVariables.isMember(basic));
                 [ -  - ]
     100 [ -  + ][ -  + ]:     103262 :   Assert(checkBasicForConflict(basic));
                 [ -  - ]
     101                 :            : 
     102                 :     103262 :   ConstraintCP conflicted = generateConflictForBasic(basic);
     103 [ -  + ][ -  + ]:     103262 :   Assert(conflicted != NullConstraint);
                 [ -  - ]
     104                 :     103262 :   d_conflictChannel.raiseConflict(conflicted, InferenceId::ARITH_CONF_SIMPLEX);
     105                 :            : 
     106                 :     103262 :   d_conflictVariables.add(basic);
     107                 :     103262 : }
     108                 :            : 
     109                 :     103262 : ConstraintCP SimplexDecisionProcedure::generateConflictForBasic(
     110                 :            :     ArithVar basic) const
     111                 :            : {
     112 [ -  + ][ -  + ]:     103262 :   Assert(d_tableau.isBasic(basic));
                 [ -  - ]
     113 [ -  + ][ -  + ]:     103262 :   Assert(checkBasicForConflict(basic));
                 [ -  - ]
     114                 :            : 
     115         [ +  + ]:     103262 :   if (d_variables.cmpAssignmentLowerBound(basic) < 0)
     116                 :            :   {
     117 [ -  + ][ -  + ]:      52615 :     Assert(d_linEq.nonbasicsAtUpperBounds(basic));
                 [ -  - ]
     118                 :      52615 :     return d_linEq.generateConflictBelowLowerBound(
     119                 :     105230 :         nodeManager(), basic, *d_conflictBuilder);
     120                 :            :   }
     121         [ +  - ]:      50647 :   else if (d_variables.cmpAssignmentUpperBound(basic) > 0)
     122                 :            :   {
     123 [ -  + ][ -  + ]:      50647 :     Assert(d_linEq.nonbasicsAtLowerBounds(basic));
                 [ -  - ]
     124                 :      50647 :     return d_linEq.generateConflictAboveUpperBound(
     125                 :     101294 :         nodeManager(), basic, *d_conflictBuilder);
     126                 :            :   }
     127                 :            :   else
     128                 :            :   {
     129                 :          0 :     Unreachable();
     130                 :            :     return NullConstraint;
     131                 :            :   }
     132                 :            : }
     133                 :          0 : bool SimplexDecisionProcedure::maybeGenerateConflictForBasic(
     134                 :            :     ArithVar basic) const
     135                 :            : {
     136         [ -  - ]:          0 :   if (checkBasicForConflict(basic))
     137                 :            :   {
     138                 :          0 :     ConstraintCP conflicted = generateConflictForBasic(basic);
     139                 :          0 :     d_conflictChannel.raiseConflict(conflicted, InferenceId::UNKNOWN);
     140                 :          0 :     return true;
     141                 :            :   }
     142                 :            :   else
     143                 :            :   {
     144                 :          0 :     return false;
     145                 :            :   }
     146                 :            : }
     147                 :            : 
     148                 :    1268440 : bool SimplexDecisionProcedure::checkBasicForConflict(ArithVar basic) const
     149                 :            : {
     150 [ -  + ][ -  + ]:    1268440 :   Assert(d_tableau.isBasic(basic));
                 [ -  - ]
     151 [ -  + ][ -  + ]:    1268440 :   Assert(d_linEq.basicIsTracked(basic));
                 [ -  - ]
     152                 :            : 
     153         [ +  + ]:    1268440 :   if (d_variables.cmpAssignmentLowerBound(basic) < 0)
     154                 :            :   {
     155         [ +  + ]:     637771 :     if (d_linEq.nonbasicsAtUpperBounds(basic))
     156                 :            :     {
     157                 :     157845 :       return true;
     158                 :            :     }
     159                 :            :   }
     160         [ +  - ]:     630669 :   else if (d_variables.cmpAssignmentUpperBound(basic) > 0)
     161                 :            :   {
     162         [ +  + ]:     630669 :     if (d_linEq.nonbasicsAtLowerBounds(basic))
     163                 :            :     {
     164                 :     151941 :       return true;
     165                 :            :     }
     166                 :            :   }
     167                 :     958654 :   return false;
     168                 :            : }
     169                 :            : 
     170                 :       4096 : void SimplexDecisionProcedure::tearDownInfeasiblityFunction(TimerStat& timer,
     171                 :            :                                                             ArithVar tmp)
     172                 :            : {
     173                 :       4096 :   TimerStat::CodeTimer codeTimer(timer);
     174 [ -  + ][ -  + ]:       4096 :   Assert(tmp != ARITHVAR_SENTINEL);
                 [ -  - ]
     175 [ -  + ][ -  + ]:       4096 :   Assert(d_tableau.isBasic(tmp));
                 [ -  - ]
     176                 :            : 
     177                 :       4096 :   RowIndex ri = d_tableau.basicToRowIndex(tmp);
     178                 :       4096 :   d_linEq.stopTrackingRowIndex(ri);
     179                 :       4096 :   d_tableau.removeBasicRow(tmp);
     180                 :       4096 :   releaseVariable(tmp);
     181                 :       4096 : }
     182                 :            : 
     183                 :          0 : void SimplexDecisionProcedure::shrinkInfeasFunc(TimerStat& timer,
     184                 :            :                                                 ArithVar inf,
     185                 :            :                                                 const ArithVarVec& dropped)
     186                 :            : {
     187                 :          0 :   TimerStat::CodeTimer codeTimer(timer);
     188                 :          0 :   for (ArithVarVec::const_iterator i = dropped.begin(), i_end = dropped.end();
     189         [ -  - ]:          0 :        i != i_end;
     190                 :          0 :        ++i)
     191                 :            :   {
     192                 :          0 :     ArithVar back = *i;
     193                 :            : 
     194                 :          0 :     int focusSgn = d_errorSet.focusSgn(back);
     195                 :          0 :     Rational chg(-focusSgn);
     196                 :            : 
     197                 :          0 :     d_linEq.substitutePlusTimesConstant(inf, back, chg);
     198                 :          0 :   }
     199                 :          0 : }
     200                 :            : 
     201                 :       7918 : void SimplexDecisionProcedure::adjustInfeasFunc(
     202                 :            :     TimerStat& timer, ArithVar inf, const AVIntPairVec& focusChanges)
     203                 :            : {
     204                 :       7918 :   TimerStat::CodeTimer codeTimer(timer);
     205                 :      15836 :   for (AVIntPairVec::const_iterator i = focusChanges.begin(),
     206                 :       7918 :                                     i_end = focusChanges.end();
     207         [ +  + ]:      17498 :        i != i_end;
     208                 :       9580 :        ++i)
     209                 :            :   {
     210                 :       9580 :     ArithVar v = (*i).first;
     211                 :       9580 :     int focusChange = (*i).second;
     212                 :            : 
     213                 :       9580 :     Rational chg(focusChange);
     214         [ +  + ]:       9580 :     if (d_tableau.isBasic(v))
     215                 :            :     {
     216                 :       5039 :       d_linEq.substitutePlusTimesConstant(inf, v, chg);
     217                 :            :     }
     218                 :            :     else
     219                 :            :     {
     220                 :       4541 :       d_linEq.directlyAddToCoefficient(inf, v, chg);
     221                 :            :     }
     222                 :       9580 :   }
     223                 :       7918 : }
     224                 :            : 
     225                 :          0 : void SimplexDecisionProcedure::addToInfeasFunc(TimerStat& timer,
     226                 :            :                                                ArithVar inf,
     227                 :            :                                                ArithVar e)
     228                 :            : {
     229                 :          0 :   AVIntPairVec justE;
     230                 :          0 :   int sgn = d_errorSet.getSgn(e);
     231                 :          0 :   justE.push_back(make_pair(e, sgn));
     232                 :          0 :   adjustInfeasFunc(timer, inf, justE);
     233                 :          0 : }
     234                 :            : 
     235                 :          0 : void SimplexDecisionProcedure::removeFromInfeasFunc(TimerStat& timer,
     236                 :            :                                                     ArithVar inf,
     237                 :            :                                                     ArithVar e)
     238                 :            : {
     239                 :          0 :   AVIntPairVec justE;
     240                 :          0 :   int opSgn = -d_errorSet.getSgn(e);
     241                 :          0 :   justE.push_back(make_pair(e, opSgn));
     242                 :          0 :   adjustInfeasFunc(timer, inf, justE);
     243                 :          0 : }
     244                 :            : 
     245                 :       4096 : ArithVar SimplexDecisionProcedure::constructInfeasiblityFunction(
     246                 :            :     TimerStat& timer, const ArithVarVec& set)
     247                 :            : {
     248         [ +  - ]:       8192 :   Trace("constructInfeasiblityFunction")
     249                 :       4096 :       << "constructInfeasiblityFunction start" << endl;
     250                 :            : 
     251                 :       4096 :   TimerStat::CodeTimer codeTimer(timer);
     252 [ -  + ][ -  + ]:       4096 :   Assert(!d_errorSet.focusEmpty());
                 [ -  - ]
     253 [ -  + ][ -  + ]:       4096 :   Assert(debugIsASet(set));
                 [ -  - ]
     254                 :            : 
     255                 :       4096 :   ArithVar inf = requestVariable();
     256 [ -  + ][ -  + ]:       4096 :   Assert(inf != ARITHVAR_SENTINEL);
                 [ -  - ]
     257                 :            : 
     258                 :       4096 :   std::vector<Rational> coeffs;
     259                 :       4096 :   std::vector<ArithVar> variables;
     260                 :            : 
     261                 :       4096 :   for (ArithVarVec::const_iterator iter = set.begin(), iend = set.end();
     262         [ +  + ]:      13509 :        iter != iend;
     263                 :       9413 :        ++iter)
     264                 :            :   {
     265                 :       9413 :     ArithVar e = *iter;
     266                 :            : 
     267 [ -  + ][ -  + ]:       9413 :     Assert(d_tableau.isBasic(e));
                 [ -  - ]
     268 [ -  + ][ -  + ]:       9413 :     Assert(!d_variables.assignmentIsConsistent(e));
                 [ -  - ]
     269                 :            : 
     270                 :       9413 :     int sgn = d_errorSet.getSgn(e);
     271 [ +  + ][ +  - ]:       9413 :     Assert(sgn == -1 || sgn == 1);
         [ -  + ][ -  + ]
                 [ -  - ]
     272         [ +  + ]:       9413 :     const Rational& violatedCoeff = sgn < 0 ? d_negOne : d_posOne;
     273                 :       9413 :     coeffs.push_back(violatedCoeff);
     274                 :       9413 :     variables.push_back(e);
     275                 :            : 
     276         [ +  - ]:       9413 :     Trace("constructInfeasiblityFunction") << violatedCoeff << " " << e << endl;
     277                 :            :   }
     278                 :       4096 :   d_tableau.addRow(inf, coeffs, variables);
     279                 :       4096 :   DeltaRational newAssignment = d_linEq.computeRowValue(inf, false);
     280                 :       4096 :   d_variables.setAssignment(inf, newAssignment);
     281                 :            : 
     282                 :            :   // d_linEq.trackVariable(inf);
     283                 :       4096 :   d_linEq.trackRowIndex(d_tableau.basicToRowIndex(inf));
     284                 :            : 
     285         [ +  - ]:       4096 :   Trace("constructInfeasiblityFunction") << inf << " " << newAssignment << endl;
     286         [ +  - ]:       8192 :   Trace("constructInfeasiblityFunction")
     287                 :       4096 :       << "constructInfeasiblityFunction done" << endl;
     288                 :       4096 :   return inf;
     289                 :       4096 : }
     290                 :            : 
     291                 :       4043 : ArithVar SimplexDecisionProcedure::constructInfeasiblityFunction(
     292                 :            :     TimerStat& timer)
     293                 :            : {
     294                 :       4043 :   ArithVarVec inError;
     295                 :       4043 :   d_errorSet.pushFocusInto(inError);
     296                 :       8086 :   return constructInfeasiblityFunction(timer, inError);
     297                 :       4043 : }
     298                 :            : 
     299                 :          0 : ArithVar SimplexDecisionProcedure::constructInfeasiblityFunction(
     300                 :            :     TimerStat& timer, ArithVar e)
     301                 :            : {
     302                 :          0 :   ArithVarVec justE;
     303                 :          0 :   justE.push_back(e);
     304                 :          0 :   return constructInfeasiblityFunction(timer, justE);
     305                 :          0 : }
     306                 :            : 
     307                 :          0 : void SimplexDecisionProcedure::addSgn(sgn_table& sgns,
     308                 :            :                                       ArithVar col,
     309                 :            :                                       int sgn,
     310                 :            :                                       ArithVar basic)
     311                 :            : {
     312                 :          0 :   pair<ArithVar, int> p = make_pair(col, determinizeSgn(sgn));
     313                 :          0 :   sgns[p].push_back(basic);
     314                 :          0 : }
     315                 :            : 
     316                 :          0 : void SimplexDecisionProcedure::addRowSgns(sgn_table& sgns,
     317                 :            :                                           ArithVar basic,
     318                 :            :                                           int norm)
     319                 :            : {
     320         [ -  - ]:          0 :   for (Tableau::RowIterator i = d_tableau.basicRowIterator(basic); !i.atEnd();
     321                 :          0 :        ++i)
     322                 :            :   {
     323                 :          0 :     const Tableau::Entry& entry = *i;
     324                 :          0 :     ArithVar v = entry.getColVar();
     325                 :          0 :     int sgn = (entry.getCoefficient().sgn());
     326                 :          0 :     addSgn(sgns, v, norm * sgn, basic);
     327                 :            :   }
     328                 :          0 : }
     329                 :            : 
     330                 :          0 : ArithVar SimplexDecisionProcedure::find_basic_in_sgns(const sgn_table& sgns,
     331                 :            :                                                       ArithVar col,
     332                 :            :                                                       int sgn,
     333                 :            :                                                       const DenseSet& m,
     334                 :            :                                                       bool inside)
     335                 :            : {
     336                 :          0 :   pair<ArithVar, int> p = make_pair(col, determinizeSgn(sgn));
     337                 :          0 :   sgn_table::const_iterator i = sgns.find(p);
     338                 :            : 
     339         [ -  - ]:          0 :   if (i != sgns.end())
     340                 :            :   {
     341                 :          0 :     const ArithVarVec& vec = (*i).second;
     342                 :          0 :     for (ArithVarVec::const_iterator viter = vec.begin(), vend = vec.end();
     343         [ -  - ]:          0 :          viter != vend;
     344                 :          0 :          ++viter)
     345                 :            :     {
     346                 :          0 :       ArithVar curr = *viter;
     347         [ -  - ]:          0 :       if (inside == m.isMember(curr))
     348                 :            :       {
     349                 :          0 :         return curr;
     350                 :            :       }
     351                 :            :     }
     352                 :            :   }
     353                 :          0 :   return ARITHVAR_SENTINEL;
     354                 :            : }
     355                 :            : 
     356                 :            : SimplexDecisionProcedure::sgn_table::const_iterator
     357                 :          0 : SimplexDecisionProcedure::find_sgns(const sgn_table& sgns,
     358                 :            :                                     ArithVar col,
     359                 :            :                                     int sgn)
     360                 :            : {
     361                 :          0 :   pair<ArithVar, int> p = make_pair(col, determinizeSgn(sgn));
     362                 :          0 :   return sgns.find(p);
     363                 :            : }
     364                 :            : }  // namespace arith::linear
     365                 :            : }  // namespace theory
     366                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14