LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/theory/arith/linear - simplex_update.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 44 51 86.3 %
Date: 2026-08-18 10:33:07 Functions: 17 18 94.4 %
Branches: 32 56 57.1 %

           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 provides a class for summarizing pivot proposals.
      11                 :            :  *
      12                 :            :  * This shares with the theory a Tableau, and a PartialModel that:
      13                 :            :  *  - satisfies the equalities in the Tableau, and
      14                 :            :  *  - the assignment for the non-basic variables satisfies their bounds.
      15                 :            :  * This maintains the relationship needed by the SimplexDecisionProcedure.
      16                 :            :  *
      17                 :            :  * In the language of Simplex for DPLL(T), this provides:
      18                 :            :  * - update()
      19                 :            :  * - pivotAndUpdate()
      20                 :            :  *
      21                 :            :  * This class also provides utility functions that require
      22                 :            :  * using both the Tableau and PartialModel.
      23                 :            :  */
      24                 :            : 
      25                 :            : #include "cvc5_private.h"
      26                 :            : 
      27                 :            : #pragma once
      28                 :            : 
      29                 :            : #include <optional>
      30                 :            : 
      31                 :            : #include "theory/arith/delta_rational.h"
      32                 :            : #include "theory/arith/linear/arithvar.h"
      33                 :            : #include "theory/arith/linear/constraint_forward.h"
      34                 :            : 
      35                 :            : namespace cvc5::internal {
      36                 :            : namespace theory {
      37                 :            : namespace arith::linear {
      38                 :            : 
      39                 :            : enum WitnessImprovement
      40                 :            : {
      41                 :            :   ConflictFound = 0,
      42                 :            :   ErrorDropped = 1,
      43                 :            :   FocusImproved = 2,
      44                 :            :   FocusShrank = 3,
      45                 :            :   Degenerate = 4,
      46                 :            :   BlandsDegenerate = 5,
      47                 :            :   HeuristicDegenerate = 6,
      48                 :            :   AntiProductive = 7
      49                 :            : };
      50                 :            : 
      51                 :       7918 : inline bool strongImprovement(WitnessImprovement w)
      52                 :            : {
      53                 :       7918 :   return w <= FocusImproved;
      54                 :            : }
      55                 :            : 
      56                 :      23010 : inline bool improvement(WitnessImprovement w) { return w <= FocusShrank; }
      57                 :            : 
      58                 :          0 : inline bool degenerate(WitnessImprovement w)
      59                 :            : {
      60         [ -  - ]:          0 :   switch (w)
      61                 :            :   {
      62                 :          0 :     case Degenerate:
      63                 :            :     case BlandsDegenerate:
      64                 :          0 :     case HeuristicDegenerate: return true;
      65                 :          0 :     default: return false;
      66                 :            :   }
      67                 :            : }
      68                 :            : 
      69                 :            : std::ostream& operator<<(std::ostream& out, WitnessImprovement w);
      70                 :            : 
      71                 :            : /**
      72                 :            :  * This class summarizes both potential:
      73                 :            :  * - pivot-and-update operations or
      74                 :            :  * - a pure update operation.
      75                 :            :  * This stores enough information for the various algorithms  hat consider these
      76                 :            :  * operations. These require slightly different pieces of information at
      77                 :            :  * different points so they are a bit verbose and paranoid.
      78                 :            :  */
      79                 :            : class UpdateInfo
      80                 :            : {
      81                 :            :  private:
      82                 :            :   /**
      83                 :            :    * The nonbasic variables under consideration.
      84                 :            :    * This is either the entering variable on a pivot and update
      85                 :            :    * or the variable being updated.
      86                 :            :    * This can only be set in the constructor or assignment.
      87                 :            :    *
      88                 :            :    * If this uninitialized, then this is ARITHVAR_SENTINEL.
      89                 :            :    */
      90                 :            :   ArithVar d_nonbasic;
      91                 :            : 
      92                 :            :   /**
      93                 :            :    * The sgn of the "intended" derivative (delta) of the update to d_nonbasic.
      94                 :            :    * This is either 1, -1, or 0.
      95                 :            :    * It is "intended" as the delta is always allowed to be 0.
      96                 :            :    * (See debugSgnAgreement().)
      97                 :            :    *
      98                 :            :    * If this uninitialized, then this is 0.
      99                 :            :    * If this is initialized, then it is -1 or 1.
     100                 :            :    *
     101                 :            :    * This can only be set in the constructor or assignment.
     102                 :            :    */
     103                 :            :   int d_nonbasicDirection;
     104                 :            : 
     105                 :            :   /**
     106                 :            :    * The change in the assignment of d_nonbasic.
     107                 :            :    * This is changed via the updateProposal(...) methods.
     108                 :            :    * The value needs to satisfy debugSgnAgreement() or it is in conflict.
     109                 :            :    */
     110                 :            :   std::optional<DeltaRational> d_nonbasicDelta;
     111                 :            : 
     112                 :            :   /**
     113                 :            :    * This is true if the pivot-and-update is *known* to cause a conflict.
     114                 :            :    * This can only be true if it was constructed through the static
     115                 :            :    * conflict(...) method.
     116                 :            :    */
     117                 :            :   bool d_foundConflict;
     118                 :            : 
     119                 :            :   /** This is the change in the size of the error set. */
     120                 :            :   std::optional<int> d_errorsChange;
     121                 :            : 
     122                 :            :   /** This is the sgn of the change in the value of the focus set.*/
     123                 :            :   std::optional<int> d_focusDirection;
     124                 :            : 
     125                 :            :   /** This is the sgn of the change in the value of the focus set.*/
     126                 :            :   std::optional<DeltaRational> d_focusChange;
     127                 :            : 
     128                 :            :   /** This is the coefficient in the tableau for the entry.*/
     129                 :            :   std::optional<const Rational*> d_tableauCoefficient;
     130                 :            : 
     131                 :            :   /**
     132                 :            :    * This is the constraint that nonbasic is basic is updating s.t. its variable
     133                 :            :    * is against it. This has 3 different possibilities:
     134                 :            :    * - Unbounded : then this is NullConstraint and unbounded() is true.
     135                 :            :    * - Pivot-And-Update: then this is not NullConstraint and the variable is not
     136                 :            :    * d_nonbasic.
     137                 :            :    * - Update: then this is not NullConstraint and the variable is d_nonbasic.
     138                 :            :    */
     139                 :            :   ConstraintP d_limiting;
     140                 :            : 
     141                 :            :   WitnessImprovement d_witness;
     142                 :            : 
     143                 :            :   /**
     144                 :            :    * This returns true if
     145                 :            :    * d_nonbasicDelta is zero() or its sgn() must agree with d_nonbasicDirection.
     146                 :            :    */
     147                 :      96275 :   bool debugSgnAgreement() const
     148                 :            :   {
     149                 :      96275 :     int deltaSgn = d_nonbasicDelta.value().sgn();
     150 [ +  + ][ +  - ]:      96275 :     return deltaSgn == 0 || deltaSgn == d_nonbasicDirection;
     151                 :            :   }
     152                 :            : 
     153                 :            :   /** This private constructor allows for setting conflict to true. */
     154                 :            :   UpdateInfo(bool conflict,
     155                 :            :              ArithVar nb,
     156                 :            :              const DeltaRational& delta,
     157                 :            :              const Rational& r,
     158                 :            :              ConstraintP lim);
     159                 :            : 
     160                 :            :  public:
     161                 :            :   /** This constructs an uninitialized UpdateInfo. */
     162                 :            :   UpdateInfo();
     163                 :            : 
     164                 :            :   /**
     165                 :            :    * This constructs an initialized UpdateInfo.
     166                 :            :    * dir must be 1 or -1.
     167                 :            :    */
     168                 :            :   UpdateInfo(ArithVar nb, int dir);
     169                 :            : 
     170                 :            :   /**
     171                 :            :    * This updates the nonBasicDelta to d and limiting to NullConstraint.
     172                 :            :    * This describes an unbounded() update.
     173                 :            :    */
     174                 :            :   void updateUnbounded(const DeltaRational& d, int ec, int f);
     175                 :            : 
     176                 :            :   void updatePureFocus(const DeltaRational& d, ConstraintP c);
     177                 :            :   // void updatePureError(const DeltaRational& d, Constraint c, int e);
     178                 :            :   // void updatePure(const DeltaRational& d, Constraint c, int e, int f);
     179                 :            : 
     180                 :            :   /**
     181                 :            :    * This updates the nonBasicDelta to d and limiting to c.
     182                 :            :    * This clears errorChange() and focusDir().
     183                 :            :    */
     184                 :            :   void updatePivot(const DeltaRational& d, ConstraintP c);
     185                 :            : 
     186                 :            :   /**
     187                 :            :    * This updates the nonBasicDelta to d, limiting to c, and errorChange to e.
     188                 :            :    * This clears focusDir().
     189                 :            :    */
     190                 :            :   void updatePivot(const DeltaRational& d,
     191                 :            :                    const Rational& r,
     192                 :            :                    ConstraintP c,
     193                 :            :                    int e);
     194                 :            : 
     195                 :            :   /**
     196                 :            :    * This updates the nonBasicDelta to d, limiting to c, errorChange to e and
     197                 :            :    * focusDir to f.
     198                 :            :    */
     199                 :            :   void witnessedUpdate(const DeltaRational& d, ConstraintP c, int e, int f);
     200                 :            :   void update(
     201                 :            :       const DeltaRational& d, const Rational& r, ConstraintP c, int e, int f);
     202                 :            : 
     203                 :            :   static UpdateInfo conflict(ArithVar nb,
     204                 :            :                              const DeltaRational& delta,
     205                 :            :                              const Rational& r,
     206                 :            :                              ConstraintP lim);
     207                 :            : 
     208                 :     506325 :   inline ArithVar nonbasic() const { return d_nonbasic; }
     209                 :      72587 :   inline bool uninitialized() const { return d_nonbasic == ARITHVAR_SENTINEL; }
     210                 :            : 
     211                 :            :   /**
     212                 :            :    * There is no limiting value to the improvement of the focus.
     213                 :            :    * If this is true, this never describes an update.
     214                 :            :    */
     215                 :    1392798 :   inline bool unbounded() const { return d_limiting == NullConstraint; }
     216                 :            : 
     217                 :            :   /**
     218                 :            :    * The update either describes a pivotAndUpdate operation
     219                 :            :    * or it describes just an update.
     220                 :            :    */
     221                 :            :   bool describesPivot() const;
     222                 :            : 
     223                 :            :   /** Returns the . describesPivot() must be true. */
     224                 :            :   ArithVar leaving() const;
     225                 :            : 
     226                 :            :   /**
     227                 :            :    * Returns true if this is *known* to find a conflict.
     228                 :            :    * If true, this must have been made through the static conflict(...)
     229                 :            :    * function.
     230                 :            :    */
     231                 :         27 :   bool foundConflict() const { return d_foundConflict; }
     232                 :            : 
     233                 :            :   /** Returns the direction nonbasic is supposed to move. */
     234                 :     106452 :   inline int nonbasicDirection() const { return d_nonbasicDirection; }
     235                 :            : 
     236                 :            :   /** Requires errorsChange to be set through setErrorsChange or updateProposal.
     237                 :            :    */
     238                 :      88626 :   inline int errorsChange() const { return d_errorsChange.value(); }
     239                 :            : 
     240                 :            :   /**
     241                 :            :    * If errorsChange has been set, return errorsChange().
     242                 :            :    * Otherwise, return def.
     243                 :            :    */
     244                 :      28322 :   inline int errorsChangeSafe(int def) const
     245                 :            :   {
     246         [ +  - ]:      28322 :     if (d_errorsChange)
     247                 :            :     {
     248                 :      28322 :       return d_errorsChange.value();
     249                 :            :     }
     250                 :            :     else
     251                 :            :     {
     252                 :          0 :       return def;
     253                 :            :     }
     254                 :            :   }
     255                 :            : 
     256                 :            :   /** Sets the errorChange. */
     257                 :            :   void setErrorsChange(int ec)
     258                 :            :   {
     259                 :            :     d_errorsChange = ec;
     260                 :            :     updateWitness();
     261                 :            :   }
     262                 :            : 
     263                 :            :   /** Requires errorsChange to be set through setErrorsChange or updateProposal.
     264                 :            :    */
     265                 :      65524 :   inline int focusDirection() const { return d_focusDirection.value(); }
     266                 :            : 
     267                 :            :   /** Sets the focusDirection. */
     268                 :            :   void setFocusDirection(int fd)
     269                 :            :   {
     270                 :            :     Assert(-1 <= fd && fd <= 1);
     271                 :            :     d_focusDirection = fd;
     272                 :            :     updateWitness();
     273                 :            :   }
     274                 :            : 
     275                 :            :   /**
     276                 :            :    * nonbasicDirection must be the same as the sign for the focus function's
     277                 :            :    * coefficient for this to be safe.
     278                 :            :    * The burden for this being safe is on the user!
     279                 :            :    */
     280                 :            :   void determineFocusDirection()
     281                 :            :   {
     282                 :            :     const int deltaSgn = d_nonbasicDelta.value().sgn();
     283                 :            :     setFocusDirection(deltaSgn * d_nonbasicDirection);
     284                 :            :   }
     285                 :            : 
     286                 :            :   /** Requires nonbasicDelta to be set through updateProposal(...). */
     287                 :        139 :   const DeltaRational& nonbasicDelta() const { return d_nonbasicDelta.value(); }
     288                 :     106452 :   const Rational& getCoefficient() const
     289                 :            :   {
     290 [ -  + ][ -  + ]:     106452 :     Assert(describesPivot());
                 [ -  - ]
     291 [ -  + ][ -  + ]:     106452 :     Assert(d_tableauCoefficient.value() != nullptr);
                 [ -  - ]
     292                 :     106452 :     return *(d_tableauCoefficient.value());
     293                 :            :   }
     294                 :            :   int basicDirection() const
     295                 :            :   {
     296                 :            :     return nonbasicDirection() * (getCoefficient().sgn());
     297                 :            :   }
     298                 :            : 
     299                 :            :   /** Returns the limiting constraint. */
     300                 :     114231 :   inline ConstraintP limiting() const { return d_limiting; }
     301                 :            : 
     302                 :     214172 :   WitnessImprovement getWitness(bool useBlands = false) const
     303                 :            :   {
     304 [ -  + ][ -  + ]:     214172 :     Assert(d_witness == computeWitness());
                 [ -  - ]
     305                 :            : 
     306         [ +  + ]:     214172 :     if (d_witness == Degenerate)
     307                 :            :     {
     308         [ -  + ]:      83226 :       if (useBlands)
     309                 :            :       {
     310                 :          0 :         return BlandsDegenerate;
     311                 :            :       }
     312                 :            :       else
     313                 :            :       {
     314                 :      83226 :         return HeuristicDegenerate;
     315                 :            :       }
     316                 :            :     }
     317                 :            :     else
     318                 :            :     {
     319                 :     130946 :       return d_witness;
     320                 :            :     }
     321                 :            :   }
     322                 :            : 
     323                 :            :   const DeltaRational& focusChange() const { return d_focusChange.value(); }
     324                 :            :   void setFocusChange(const DeltaRational& fc) { d_focusChange = fc; }
     325                 :            : 
     326                 :            :   /** Outputs the UpdateInfo into out. */
     327                 :            :   void output(std::ostream& out) const;
     328                 :            : 
     329                 :            :  private:
     330                 :      96275 :   void updateWitness()
     331                 :            :   {
     332                 :      96275 :     d_witness = computeWitness();
     333 [ +  + ][ +  - ]:      96275 :     Assert(describesPivot() || improvement(d_witness));
         [ -  + ][ -  + ]
                 [ -  - ]
     334                 :      96275 :   }
     335                 :            : 
     336                 :            :   /**
     337                 :            :    * Determines the appropriate WitnessImprovement for the update.
     338                 :            :    * useBlands breaks ties for degenerate pivots.
     339                 :            :    *
     340                 :            :    * This is safe if:
     341                 :            :    * - d_foundConflict is true, or
     342                 :            :    * - d_foundConflict is false and d_errorsChange has been set and
     343                 :            :    * d_errorsChange < 0, or
     344                 :            :    * - d_foundConflict is false and d_errorsChange has been set and
     345                 :            :    * d_errorsChange >= 0 and d_focusDirection has been set.
     346                 :            :    */
     347                 :     310447 :   WitnessImprovement computeWitness() const
     348                 :            :   {
     349         [ +  + ]:     310447 :     if (d_foundConflict)
     350                 :            :     {
     351                 :         81 :       return ConflictFound;
     352                 :            :     }
     353 [ +  - ][ +  + ]:     310366 :     else if (d_errorsChange && d_errorsChange.value() < 0)
                 [ +  + ]
     354                 :            :     {
     355                 :     145352 :       return ErrorDropped;
     356                 :            :     }
     357         [ +  + ]:     165014 :     else if (d_errorsChange.value_or(0) == 0)
     358                 :            :     {
     359         [ +  - ]:     160948 :       if (d_focusDirection)
     360                 :            :       {
     361         [ +  + ]:     160948 :         if (*d_focusDirection > 0)
     362                 :            :         {
     363                 :      36997 :           return FocusImproved;
     364                 :            :         }
     365         [ +  + ]:     123951 :         else if (*d_focusDirection == 0)
     366                 :            :         {
     367                 :     123873 :           return Degenerate;
     368                 :            :         }
     369                 :            :       }
     370                 :            :     }
     371                 :       4144 :     return AntiProductive;
     372                 :            :   }
     373                 :            : };
     374                 :            : 
     375                 :            : std::ostream& operator<<(std::ostream& out, const UpdateInfo& up);
     376                 :            : 
     377                 :            : }  // namespace arith::linear
     378                 :            : }  // namespace theory
     379                 :            : }  // namespace cvc5::internal

Generated by: LCOV version 1.14