4 #include <carl-arith/poly/umvpoly/functions/Derivative.h>
5 #include <carl-arith/poly/umvpoly/functions/SoSDecomposition.h>
6 #include <carl-arith/constraint/IntervalEvaluation.h>
8 #include <carl-arith/vs/Substitution.h>
10 //#define VS_DEBUG_SUBSTITUTION
11 const unsigned MAX_NUM_OF_TERMS = 512;
14 namespace carl::vs::detail
16 template <class combineType>
17 bool combine( const std::vector< std::vector< std::vector< combineType > > >& _toCombine, std::vector< std::vector< combineType > >& _combination )
19 // Initialize the current combination. If there is nothing to combine or an empty vector to combine with, return the empty vector.
20 if( _toCombine.empty() ) return true;
21 std::vector<typename std::vector< std::vector< combineType > >::const_iterator > combination
22 = std::vector<typename std::vector< std::vector< combineType > >::const_iterator >();
23 unsigned estimatedResultSize = 1;
24 for( auto iter = _toCombine.begin(); iter != _toCombine.end(); ++iter )
28 estimatedResultSize *= (unsigned)iter->size();
29 if( estimatedResultSize > MAX_NUM_OF_COMBINATION_RESULT )
32 combination.push_back( iter->begin() );
34 // As long as no more combination for the last vector in first vector of vectors exists.
35 bool lastCombinationReached = false;
36 while( !lastCombinationReached )
38 // Create a new combination of vectors.
39 _combination.push_back( std::vector< combineType >() );
40 bool previousCounterIncreased = false;
41 // For each vector in the vector of vectors, choose a vector. Finally we combine
42 // those vectors by merging them to a new vector and add this to the result.
43 auto currentVector = _toCombine.begin();
44 for( auto combineElement = combination.begin(); combineElement != combination.end(); ++combineElement )
46 // Add the current vectors elements to the combination.
47 _combination.back().insert( _combination.back().end(), (*combineElement)->begin(), (*combineElement)->end() );
49 if( !previousCounterIncreased )
52 if( *combineElement != currentVector->end() )
53 previousCounterIncreased = true;
56 if( combineElement != --combination.end() )
57 *combineElement = currentVector->begin();
59 lastCombinationReached = true;
68 template<typename Poly>
69 void simplify( CaseDistinction<Poly>& _toSimplify )
71 bool containsEmptyDisjunction = false;
72 auto conj = _toSimplify.begin();
73 while( conj != _toSimplify.end() )
75 bool conjInconsistent = false;
76 auto cons = (*conj).begin();
77 while( cons != (*conj).end() )
79 if( *cons == Constraint<Poly>( false ) )
81 conjInconsistent = true;
84 else if( *cons == Constraint<Poly>( true ) )
85 cons = (*conj).erase( cons );
89 bool conjEmpty = (*conj).empty();
90 if( conjInconsistent || (containsEmptyDisjunction && conjEmpty) )
92 // Delete the conjunction.
94 conj = _toSimplify.erase( conj );
98 if( !containsEmptyDisjunction && conjEmpty )
99 containsEmptyDisjunction = true;
103 template<typename Poly>
104 void simplify( CaseDistinction<Poly>& _toSimplify, Variables& _conflictingVars, const detail::EvalDoubleIntervalMap& _solutionSpace )
106 bool containsEmptyDisjunction = false;
107 auto conj = _toSimplify.begin();
108 while( conj != _toSimplify.end() )
110 bool conjInconsistent = false;
111 auto cons = (*conj).begin();
112 while( cons != (*conj).end() )
114 if( *cons == Constraint<Poly>( false ) )
116 conjInconsistent = true;
119 else if( *cons == Constraint<Poly>( true ) )
120 cons = (*conj).erase( cons );
123 unsigned conflictingWithSolutionSpace = consistent_with(cons->constr(), _solutionSpace );
125 // std::cout << "Is " << cons << std::endl;
126 // std::cout << std::endl;
127 // std::cout << "consistent with " << std::endl;
128 // for( auto iter = _solutionSpace.begin(); iter != _solutionSpace.end(); ++iter )
129 // std::cout << iter->first << " in " << iter->second << std::endl;
130 // std::cout << " -> " << conflictingWithSolutionSpace << std::endl;
132 if( conflictingWithSolutionSpace == 0 )
134 auto vars = variables(*cons);
135 _conflictingVars.insert( vars.begin(), vars.end() );
136 conjInconsistent = true;
139 else if( conflictingWithSolutionSpace == 1 )
140 cons = (*conj).erase( cons );
145 bool conjEmpty = (*conj).empty();
146 if( conjInconsistent || (containsEmptyDisjunction && conjEmpty) )
148 // Delete the conjunction.
150 conj = _toSimplify.erase( conj );
154 if( !containsEmptyDisjunction && conjEmpty )
155 containsEmptyDisjunction = true;
159 template<typename Poly>
160 bool splitProducts( CaseDistinction<Poly>& _toSimplify, bool _onlyNeq )
162 std::map<const Constraint<Poly>, CaseDistinction<Poly>> result_cache;
164 size_t toSimpSize = _toSimplify.size();
165 for( size_t pos = 0; pos < toSimpSize; )
167 if( !_toSimplify.begin()->empty() )
169 CaseDistinction<Poly> temp;
170 if( !splitProducts( _toSimplify[pos], temp, result_cache, _onlyNeq ) )
172 _toSimplify.erase( _toSimplify.begin() );
173 _toSimplify.insert( _toSimplify.end(), temp.begin(), temp.end() );
182 template<typename Poly>
183 bool splitProducts( const ConstraintConjunction<Poly>& _toSimplify, CaseDistinction<Poly>& _result, std::map<const Constraint<Poly>, CaseDistinction<Poly>>& result_cache, bool _onlyNeq )
185 std::vector<CaseDistinction<Poly>> toCombine;
186 for( auto constraint = _toSimplify.begin(); constraint != _toSimplify.end(); ++constraint )
188 auto i = result_cache.find(*constraint);
189 if (i == result_cache.end()) {
190 auto res = splitProducts(*constraint, _onlyNeq);
191 i = result_cache.emplace(*constraint, res).first;
193 toCombine.push_back(i->second);
196 if( !combine( toCombine, _result ) )
202 template<typename Poly>
203 CaseDistinction<Poly> splitProducts( const Constraint<Poly>& _constraint, bool _onlyNeq )
205 CaseDistinction<Poly> result;
206 auto& factorization = _constraint.lhs_factorization();
207 if( !carl::is_trivial(factorization) )
209 switch( _constraint.relation() )
215 for( auto factor = factorization.begin(); factor != factorization.end(); ++factor )
217 result.emplace_back();
218 result.back().push_back( Constraint<Poly>( factor->first, Relation::EQ ) );
223 result.emplace_back();
224 result.back().push_back( _constraint );
231 result.emplace_back();
232 for( auto factor = factorization.begin(); factor != factorization.end(); ++factor )
233 result.back().push_back( Constraint<Poly>( factor->first, Relation::NEQ ) );
241 result = getSignCombinations( _constraint );
246 result.emplace_back();
247 result.back().push_back( _constraint );
255 result.emplace_back();
256 result.back().push_back( _constraint );
261 template<typename Poly>
262 void splitSosDecompositions( CaseDistinction<Poly>& _toSimplify )
264 // TODO this needs to be reviewed and fixed
265 // It seems that is is assumed that lcoeffNeg * constraint.lhs() is positive if
266 // a SOS decomposition exists. However, we can only follow that it's non-negative
267 // (in the univariate case), for the multivariate case more requirements need to be made
268 // (therefor constraint.lhs().has_constant_term() ???).
269 // This lead to wrong simplifications in very rare cases, for example
270 // -100 + 140*z + -49*y^2 + -49*z^2 is wrongly simplified to true (see McsatVSBug).
272 // Temporarily disabled (what can be followed in the multivariate case?).
275 for( size_t i = 0; i < _toSimplify.size(); )
277 auto& cc = _toSimplify[i];
278 bool foundNoInvalidConstraint = true;
280 while( foundNoInvalidConstraint && pos < cc.size() )
282 const Constraint<Poly>& constraint = cc[pos];
283 std::vector<std::pair<typename Poly::NumberType,Poly>> sosDec;
284 bool lcoeffNeg = carl::is_negative(constraint.lhs().lcoeff());
286 sosDec = carl::sos_decomposition(-constraint.lhs());
288 sosDec = carl::sos_decomposition(constraint.lhs());
289 if( sosDec.size() > 1 )
291 // std::cout << "Sum-of-squares decomposition of " << constraint.lhs() << " = " << sosDec << std::endl;
292 bool addSquares = true;
293 bool constraintValid = false;
294 switch( constraint.relation() )
296 case carl::Relation::EQ:
298 if( constraint.lhs().has_constant_term() )
300 foundNoInvalidConstraint = false;
305 case carl::Relation::NEQ:
308 if( constraint.lhs().has_constant_term() )
310 constraintValid = true;
314 case carl::Relation::LEQ:
319 constraintValid = true;
321 else if( constraint.lhs().has_constant_term() )
324 foundNoInvalidConstraint = false;
328 case carl::Relation::LESS:
333 if( constraint.lhs().has_constant_term() )
334 constraintValid = true;
337 foundNoInvalidConstraint = false;
340 case carl::Relation::GEQ:
345 constraintValid = true;
347 else if( constraint.lhs().has_constant_term() )
350 foundNoInvalidConstraint = false;
356 assert( constraint.relation() == carl::Relation::GREATER );
359 foundNoInvalidConstraint = false;
362 if( constraint.lhs().has_constant_term() )
363 constraintValid = true;
367 assert( !(!foundNoInvalidConstraint && constraintValid) );
368 assert( !(!foundNoInvalidConstraint && addSquares) );
369 if( constraintValid || addSquares )
378 for( auto it = sosDec.begin(); it != sosDec.end(); ++it )
380 cc.emplace_back( it->second, carl::Relation::EQ );
387 if( foundNoInvalidConstraint )
391 cc = _toSimplify.back();
392 _toSimplify.pop_back();
397 template<typename Poly>
398 CaseDistinction<Poly> getSignCombinations( const Constraint<Poly>& _constraint )
400 CaseDistinction<Poly> combinations;
401 auto& factorization = _constraint.lhs_factorization();
402 if( !carl::is_trivial(factorization) && factorization.size() <= MAX_PRODUCT_SPLIT_NUMBER )
404 assert( _constraint.relation() == Relation::GREATER || _constraint.relation() == Relation::LESS
405 || _constraint.relation() == Relation::GEQ || _constraint.relation() == Relation::LEQ );
406 Relation relPos = Relation::GREATER;
407 Relation relNeg = Relation::LESS;
408 if( _constraint.relation() == Relation::GEQ || _constraint.relation() == Relation::LEQ )
410 relPos = Relation::GEQ;
411 relNeg = Relation::LEQ;
413 bool positive = (_constraint.relation() == Relation::GEQ || _constraint.relation() == Relation::GREATER);
414 ConstraintConjunction<Poly> positives;
415 ConstraintConjunction<Poly> alwayspositives;
416 ConstraintConjunction<Poly> negatives;
417 ConstraintConjunction<Poly> alwaysnegatives;
418 unsigned numOfAlwaysNegatives = 0;
419 for( auto factor = factorization.begin(); factor != factorization.end(); ++factor )
421 Constraint<Poly> consPos = Constraint<Poly>( factor->first, relPos );
422 unsigned posConsistent = consPos.is_consistent();
423 if( posConsistent != 0 )
424 positives.push_back( consPos );
425 Constraint<Poly> consNeg = Constraint<Poly>( factor->first, relNeg );
426 unsigned negConsistent = consNeg.is_consistent();
427 if( negConsistent == 0 )
429 if( posConsistent == 0 )
431 combinations.emplace_back();
432 combinations.back().push_back( consNeg );
435 if( posConsistent != 1 )
436 alwayspositives.push_back( positives.back() );
437 positives.pop_back();
441 if( posConsistent == 0 )
443 ++numOfAlwaysNegatives;
444 if( negConsistent != 1 )
445 alwaysnegatives.push_back( consNeg );
447 else negatives.push_back( consNeg );
450 assert( positives.size() == negatives.size() );
451 if( positives.size() > 0 )
453 std::vector< std::bitset<MAX_PRODUCT_SPLIT_NUMBER> > combSelector = std::vector< std::bitset<MAX_PRODUCT_SPLIT_NUMBER> >();
454 if( fmod( numOfAlwaysNegatives, 2.0 ) != 0.0 )
457 getOddBitStrings( positives.size(), combSelector );
459 getEvenBitStrings( positives.size(), combSelector );
464 getEvenBitStrings( positives.size(), combSelector );
466 getOddBitStrings( positives.size(), combSelector );
468 for( auto comb = combSelector.begin(); comb != combSelector.end(); ++comb )
470 combinations.emplace_back( alwaysnegatives );
471 combinations.back().insert( combinations.back().end(), alwayspositives.begin(), alwayspositives.end() );
472 for( unsigned pos = 0; pos < positives.size(); ++pos )
475 combinations.back().push_back( negatives[pos] );
477 combinations.back().push_back( positives[pos] );
483 combinations.emplace_back( alwaysnegatives );
484 combinations.back().insert( combinations.back().end(), alwayspositives.begin(), alwayspositives.end() );
489 combinations.emplace_back();
490 combinations.back().push_back( _constraint );
495 void getOddBitStrings( std::size_t _length, std::vector< std::bitset<MAX_PRODUCT_SPLIT_NUMBER> >& _strings )
497 assert( _length > 0 );
498 if( _length == 1 ) _strings.push_back( std::bitset<MAX_PRODUCT_SPLIT_NUMBER>( 1 ) );
501 std::size_t pos = _strings.size();
502 getEvenBitStrings( _length - 1, _strings );
503 for( ; pos < _strings.size(); ++pos )
506 _strings[pos].flip(0);
508 getOddBitStrings( _length - 1, _strings );
509 for( ; pos < _strings.size(); ++pos ) _strings[pos] <<= 1;
513 void getEvenBitStrings( std::size_t _length, std::vector< std::bitset<MAX_PRODUCT_SPLIT_NUMBER> >& _strings )
515 assert( _length > 0 );
516 if( _length == 1 ) _strings.push_back( std::bitset<MAX_PRODUCT_SPLIT_NUMBER>( 0 ) );
519 std::size_t pos = _strings.size();
520 getEvenBitStrings( _length - 1, _strings );
521 for( ; pos < _strings.size(); ++pos ) _strings[pos] <<= 1;
522 getOddBitStrings( _length - 1, _strings );
523 for( ; pos < _strings.size(); ++pos )
526 _strings[pos].flip(0);
531 template<typename Poly>
532 void print( CaseDistinction<Poly>& _substitutionResults )
534 auto conj = _substitutionResults.begin();
535 while( conj != _substitutionResults.end() )
537 if( conj != _substitutionResults.begin() )
538 std::cout << " or (";
541 auto cons = (*conj).begin();
542 while( cons != (*conj).end() )
544 if( cons != (*conj).begin() )
545 std::cout << " and ";
549 std::cout << ")" << std::endl;
552 std::cout << std::endl;
555 template<typename Poly>
556 bool substitute( const Constraint<Poly>& _cons,
557 const Substitution<Poly>& _subs,
558 CaseDistinction<Poly>& _result,
559 bool _accordingPaper,
560 Variables& _conflictingVariables,
561 const detail::EvalDoubleIntervalMap& _solutionSpace)
563 #ifdef VS_DEBUG_SUBSTITUTION
564 std::cout << "substitute: ( " << _cons << " )" << _subs << std::endl;
567 // Apply the substitution according to its type.
568 switch( _subs.term().type() )
570 case TermType::NORMAL:
572 result = substituteNormal( _cons, _subs, _result, _accordingPaper, _conflictingVariables, _solutionSpace );
575 case TermType::PLUS_EPSILON:
577 result = substitutePlusEps( _cons, _subs, _result, _accordingPaper, _conflictingVariables, _solutionSpace );
580 case TermType::MINUS_INFINITY:
582 substituteInf( _cons, _subs, _result, _conflictingVariables, _solutionSpace );
585 case TermType::PLUS_INFINITY:
587 substituteInf( _cons, _subs, _result, _conflictingVariables, _solutionSpace );
592 std::cout << "Error in substitute: unexpected type of substitution." << std::endl;
595 #ifdef VS_DEBUG_SUBSTITUTION
601 template<typename Poly>
602 bool substituteNormal( const Constraint<Poly>& _cons,
603 const Substitution<Poly>& _subs,
604 CaseDistinction<Poly>& _result,
605 bool _accordingPaper,
606 Variables& _conflictingVariables,
607 const detail::EvalDoubleIntervalMap& _solutionSpace )
611 if( _cons.variables().has( _subs.variable() ) )
613 using Rational = typename Poly::NumberType;
614 // Collect all necessary left hand sides to create the new conditions of all cases referring to the virtual substitution.
615 if( carl::pow( Rational(Rational(_subs.term().sqrt_ex().constant_part().size()) + Rational(_subs.term().sqrt_ex().factor().size()) * Rational(_subs.term().sqrt_ex().radicand().size())), _cons.maxDegree( _subs.variable() )) > (MAX_NUM_OF_TERMS*MAX_NUM_OF_TERMS) )
619 carl::SqrtEx sub = carl::substitute( _cons.lhs(), _subs.variable(), _subs.term().sqrt_ex() );
620 #ifdef VS_DEBUG_SUBSTITUTION
621 std::cout << "Result of common substitution:" << sub << std::endl;
623 // The term then looks like: q/s
624 if( !sub.has_sqrt() )
626 // Create the new decision tuples.
627 if( _cons.relation() == Relation::EQ || _cons.relation() == Relation::NEQ )
629 // Add conjunction (sub.constant_part() = 0) to the substitution result.
630 _result.emplace_back();
631 _result.back().push_back( Constraint<Poly>( sub.constant_part(), _cons.relation() ) );
635 if( !_subs.term().sqrt_ex().denominator().is_constant() )
637 // Add conjunction (sub.denominator()>0 and sub.constant_part() </>/<=/>= 0) to the substitution result.
638 _result.emplace_back();
639 _result.back().push_back( Constraint<Poly>( sub.denominator(), Relation::GREATER ) );
640 _result.back().push_back( Constraint<Poly>( sub.constant_part(), _cons.relation() ) );
641 // Add conjunction (sub.denominator()<0 and sub.constant_part() >/</>=/<= 0) to the substitution result.
642 Relation inverseRelation;
643 switch( _cons.relation() )
646 inverseRelation = Relation::GREATER;
648 case Relation::GREATER:
649 inverseRelation = Relation::LESS;
652 inverseRelation = Relation::GEQ;
655 inverseRelation = Relation::LEQ;
659 inverseRelation = Relation::EQ;
661 _result.emplace_back();
662 _result.back().push_back( Constraint<Poly>( sub.denominator(), Relation::LESS ) );
663 _result.back().push_back( Constraint<Poly>( sub.constant_part(), inverseRelation ) );
667 // Add conjunction (f(-c/b)*b^k </>/<=/>= 0) to the substitution result.
668 _result.emplace_back();
669 _result.back().push_back( Constraint<Poly>( sub.constant_part(), _cons.relation() ) );
673 // The term then looks like: (q+r*sqrt(b^2-4ac))/s
677 if( !_subs.term().sqrt_ex().denominator().is_constant() )
678 s = sub.denominator();
679 switch( _cons.relation() )
683 result = substituteNormalSqrtEq( sub.radicand(), sub.constant_part(), sub.factor(), _result, _accordingPaper );
688 result = substituteNormalSqrtNeq( sub.radicand(), sub.constant_part(), sub.factor(), _result, _accordingPaper );
693 result = substituteNormalSqrtLess( sub.radicand(), sub.constant_part(), sub.factor(), s, _result, _accordingPaper );
696 case Relation::GREATER:
698 result = substituteNormalSqrtLess( sub.radicand(), sub.constant_part(), sub.factor(), -s, _result, _accordingPaper );
703 result = substituteNormalSqrtLeq( sub.radicand(), sub.constant_part(), sub.factor(), s, _result, _accordingPaper );
708 result = substituteNormalSqrtLeq( sub.radicand(), sub.constant_part(), sub.factor(), -s, _result, _accordingPaper );
712 std::cout << "Error in substituteNormal: Unexpected relation symbol" << std::endl;
719 _result.emplace_back();
720 _result.back().push_back( _cons );
722 simplify( _result, _conflictingVariables, _solutionSpace );
726 template<typename Poly>
727 bool substituteNormalSqrtEq( const Poly& _radicand,
730 CaseDistinction<Poly>& _result,
731 bool _accordingPaper )
733 if( _q.size() > MAX_NUM_OF_TERMS || _r.size() > MAX_NUM_OF_TERMS || _radicand.size() > MAX_NUM_OF_TERMS )
735 Poly lhs = carl::pow(_q, 2) - carl::pow(_r, 2) * _radicand;
736 if( _accordingPaper )
739 // Add conjunction (q*r<=0 and q^2-r^2*radicand=0) to the substitution result.
740 _result.emplace_back();
741 _result.back().push_back( Constraint<Poly>( qr, Relation::LEQ ) );
742 _result.back().push_back( Constraint<Poly>( lhs, Relation::EQ ) );
746 // Add conjunction (q=0 and r=0) to the substitution result.
747 _result.emplace_back();
748 _result.back().push_back( Constraint<Poly>( _q, Relation::EQ ) );
749 _result.back().push_back( Constraint<Poly>( _r, Relation::EQ ) );
750 // Add conjunction (q=0 and radicand=0) to the substitution result.
751 _result.emplace_back();
752 _result.back().push_back( Constraint<Poly>( _q, Relation::EQ ) );
753 _result.back().push_back( Constraint<Poly>( _radicand, Relation::EQ ) );
754 // Add conjunction (q<0 and r>0 and q^2-r^2*radicand=0) to the substitution result.
755 _result.emplace_back();
756 _result.back().push_back( Constraint<Poly>( _q, Relation::LESS ) );
757 _result.back().push_back( Constraint<Poly>( _r, Relation::GREATER ) );
758 _result.back().push_back( Constraint<Poly>( lhs, Relation::EQ ) );
759 // Add conjunction (q>0 and r<0 and q^2-r^2*radicand=0) to the substitution result.
760 _result.emplace_back();
761 _result.back().push_back( Constraint<Poly>( _q, Relation::GREATER ) );
762 _result.back().push_back( Constraint<Poly>( _r, Relation::LESS ) );
763 _result.back().push_back( Constraint<Poly>( lhs, Relation::EQ ) );
768 template<typename Poly>
769 bool substituteNormalSqrtNeq( const Poly& _radicand,
772 CaseDistinction<Poly>& _result,
773 bool _accordingPaper )
775 if( _q.size() > MAX_NUM_OF_TERMS || _r.size() > MAX_NUM_OF_TERMS || _radicand.size() > MAX_NUM_OF_TERMS )
777 Poly lhs = carl::pow(_q, 2) - carl::pow(_r, 2) * _radicand;
778 if( _accordingPaper )
781 // Add conjunction (q*r>0 and q^2-r^2*radicand!=0) to the substitution result.
782 _result.emplace_back();
783 _result.back().push_back( Constraint<Poly>( qr, Relation::GREATER ) );
784 _result.back().push_back( Constraint<Poly>( lhs, Relation::NEQ ) );
788 // Add conjunction (q>0 and r>0) to the substitution result.
789 _result.emplace_back();
790 _result.back().push_back( Constraint<Poly>( _q, Relation::GREATER ) );
791 _result.back().push_back( Constraint<Poly>( _r, Relation::GREATER ) );
792 // Add conjunction (q<0 and r<0) to the substitution result.
793 _result.emplace_back();
794 _result.back().push_back( Constraint<Poly>( _q, Relation::LESS ) );
795 _result.back().push_back( Constraint<Poly>( _r, Relation::LESS ) );
796 // Add conjunction (q^2-r^2*radicand!=0) to the substitution result.
797 _result.emplace_back();
798 _result.back().push_back( Constraint<Poly>( lhs, Relation::NEQ ) );
803 template<typename Poly>
804 bool substituteNormalSqrtLess( const Poly& _radicand,
808 CaseDistinction<Poly>& _result,
809 bool _accordingPaper )
811 if( _q.size() > MAX_NUM_OF_TERMS || _r.size() > MAX_NUM_OF_TERMS || _radicand.size() > MAX_NUM_OF_TERMS )
813 Poly lhs = carl::pow(_q, 2) - carl::pow(_r, 2) * _radicand;
814 if( _accordingPaper )
818 // Add conjunction (q*s<0 and q^2-r^2*radicand>0) to the substitution result.
819 _result.emplace_back();
820 _result.back().push_back( Constraint<Poly>( qs, Relation::LESS ) );
821 _result.back().push_back( Constraint<Poly>( lhs, Relation::GREATER ) );
822 // Add conjunction (r*s<=0 and q*s<0) to the substitution result.
823 _result.emplace_back();
824 _result.back().push_back( Constraint<Poly>( rs, Relation::LEQ ) );
825 _result.back().push_back( Constraint<Poly>( qs, Relation::LESS ) );
826 // Add conjunction (r*s<=0 and q^2-r^2*radicand<0) to the substitution result.
827 _result.emplace_back();
828 _result.back().push_back( Constraint<Poly>( rs, Relation::LEQ ) );
829 _result.back().push_back( Constraint<Poly>( lhs, Relation::LESS ) );
833 // Add conjunction (q<0 and s>0 and q^2-r^2*radicand>0) to the substitution result.
834 _result.emplace_back();
835 _result.back().push_back( Constraint<Poly>( _q, Relation::LESS ) );
836 _result.back().push_back( Constraint<Poly>( _s, Relation::GREATER ) );
837 _result.back().push_back( Constraint<Poly>( lhs, Relation::GREATER ) );
838 // Add conjunction (q>0 and s<0 and q^2-r^2*radicand>0) to the substitution result.
839 _result.emplace_back();
840 _result.back().push_back( Constraint<Poly>( _q, Relation::GREATER ) );
841 _result.back().push_back( Constraint<Poly>( _s, Relation::LESS ) );
842 _result.back().push_back( Constraint<Poly>( lhs, Relation::GREATER ) );
843 // Add conjunction (r>0 and s<0 and q^2-r^2*radicand<0) to the substitution result.
844 _result.emplace_back();
845 _result.back().push_back( Constraint<Poly>( _r, Relation::GREATER ) );
846 _result.back().push_back( Constraint<Poly>( _s, Relation::LESS ) );
847 _result.back().push_back( Constraint<Poly>( lhs, Relation::LESS ) );
848 // Add conjunction (r<0 and s>0 and q^2-r^2*radicand<0) to the substitution result.
849 _result.emplace_back();
850 _result.back().push_back( Constraint<Poly>( _r, Relation::LESS ) );
851 _result.back().push_back( Constraint<Poly>( _s, Relation::GREATER ) );
852 _result.back().push_back( Constraint<Poly>( lhs, Relation::LESS ) );
853 // Add conjunction (r>=0 and q<0 and s>0) to the substitution result.
854 _result.emplace_back();
855 _result.back().push_back( Constraint<Poly>( _r, Relation::GEQ ) );
856 _result.back().push_back( Constraint<Poly>( _q, Relation::GREATER ) );
857 _result.back().push_back( Constraint<Poly>( _s, Relation::LESS ) );
858 // Add conjunction (r<=0 and q>0 and s<0) to the substitution result.
859 _result.emplace_back();
860 _result.back().push_back( Constraint<Poly>( _r, Relation::LEQ ) );
861 _result.back().push_back( Constraint<Poly>( _q, Relation::LESS ) );
862 _result.back().push_back( Constraint<Poly>( _s, Relation::GREATER ) );
867 template<typename Poly>
868 bool substituteNormalSqrtLeq( const Poly& _radicand,
872 CaseDistinction<Poly>& _result,
873 bool _accordingPaper )
875 if( _q.size() > MAX_NUM_OF_TERMS || _r.size() > MAX_NUM_OF_TERMS || _radicand.size() > MAX_NUM_OF_TERMS )
877 Poly lhs = carl::pow(_q, 2) - carl::pow(_r, 2) * _radicand;
878 if( _accordingPaper )
882 // Add conjunction (q*s<=0 and q^2-r^2*radicand>=0) to the substitution result.
883 _result.emplace_back();
884 _result.back().push_back( Constraint<Poly>( qs, Relation::LEQ ) );
885 _result.back().push_back( Constraint<Poly>( lhs, Relation::GEQ ) );
886 // Add conjunction (r*s<=0 and q^2-r^2*radicand<=0) to the substitution result.
887 _result.emplace_back();
888 _result.back().push_back( Constraint<Poly>( rs, Relation::LEQ ) );
889 _result.back().push_back( Constraint<Poly>( lhs, Relation::LEQ ) );
893 // Add conjunction (q<0 and s>0 and q^2-r^2*radicand>=0) to the substitution result.
894 _result.emplace_back();
895 _result.back().push_back( Constraint<Poly>( _q, Relation::LESS ) );
896 _result.back().push_back( Constraint<Poly>( _s, Relation::GREATER ) );
897 _result.back().push_back( Constraint<Poly>( lhs, Relation::GEQ ) );
898 // Add conjunction (q>0 and s<0 and q^2-r^2*radicand>=0) to the substitution result.
899 _result.emplace_back();
900 _result.back().push_back( Constraint<Poly>( _q, Relation::GREATER ) );
901 _result.back().push_back( Constraint<Poly>( _s, Relation::LESS ) );
902 _result.back().push_back( Constraint<Poly>( lhs, Relation::GEQ ) );
903 // Add conjunction (r>0 and s<0 and q^2-r^2*radicand<=0) to the substitution result.
904 _result.emplace_back();
905 _result.back().push_back( Constraint<Poly>( _r, Relation::GREATER ) );
906 _result.back().push_back( Constraint<Poly>( _s, Relation::LESS ) );
907 _result.back().push_back( Constraint<Poly>( lhs, Relation::LEQ ) );
908 // Add conjunction (r<0 and s>0 and q^2-r^2*radicand<=0) to the substitution result.
909 _result.emplace_back();
910 _result.back().push_back( Constraint<Poly>( _r, Relation::LESS ) );
911 _result.back().push_back( Constraint<Poly>( _s, Relation::GREATER ) );
912 _result.back().push_back( Constraint<Poly>( lhs, Relation::LEQ ) );
913 // Add conjunction (r=0 and q=0) to the substitution result.
914 _result.emplace_back();
915 _result.back().push_back( Constraint<Poly>( _r, Relation::EQ ) );
916 _result.back().push_back( Constraint<Poly>( _q, Relation::EQ ) );
917 // Add conjunction (radicand=0 and q=0) to the substitution result.
918 _result.emplace_back();
919 _result.back().push_back( Constraint<Poly>( _radicand, Relation::EQ ) );
920 _result.back().push_back( Constraint<Poly>( _q, Relation::EQ ) );
925 template<typename Poly>
926 bool substitutePlusEps( const Constraint<Poly>& _cons,
927 const Substitution<Poly>& _subs,
928 CaseDistinction<Poly>& _result,
929 bool _accordingPaper,
930 Variables& _conflictingVariables,
931 const detail::EvalDoubleIntervalMap& _solutionSpace )
934 auto vars = variables(_cons);
937 if( vars.has( _subs.variable() ) )
939 switch( _cons.relation() )
943 substituteTrivialCase( _cons, _subs, _result );
948 substituteNotTrivialCase( _cons, _subs, _result );
953 result = substituteEpsGradients( _cons, _subs, Relation::LESS, _result, _accordingPaper, _conflictingVariables, _solutionSpace );
956 case Relation::GREATER:
958 result = substituteEpsGradients( _cons, _subs, Relation::GREATER, _result, _accordingPaper, _conflictingVariables, _solutionSpace );
963 substituteTrivialCase( _cons, _subs, _result );
964 result = substituteEpsGradients( _cons, _subs, Relation::LESS, _result, _accordingPaper, _conflictingVariables, _solutionSpace );
969 substituteTrivialCase( _cons, _subs, _result );
970 result = substituteEpsGradients( _cons, _subs, Relation::GREATER, _result, _accordingPaper, _conflictingVariables, _solutionSpace );
976 simplify( _result, _conflictingVariables, _solutionSpace );
980 _result.emplace_back();
981 _result.back().push_back( _cons );
987 std::cerr << "Warning in substitutePlusEps: The chosen constraint has no variable" << std::endl;
992 template<typename Poly>
993 bool substituteEpsGradients( const Constraint<Poly>& _cons,
994 const Substitution<Poly>& _subs,
995 const Relation _relation,
996 CaseDistinction<Poly>& _result,
997 bool _accordingPaper,
998 Variables& _conflictingVariables,
999 const detail::EvalDoubleIntervalMap& _solutionSpace )
1001 assert( _cons.variables().has( _subs.variable() ) );
1002 // Create a substitution formed by the given one without an addition of epsilon.
1003 auto term = Term<Poly>::normal(_subs.term().sqrt_ex());
1004 // Call the method substituteNormal with the constraint f(x)~0 and the substitution [x -> t], where the parameter relation is ~.
1005 Constraint<Poly> firstCaseInequality = Constraint<Poly>( _cons.lhs(), _relation );
1006 if( !substituteNormal( firstCaseInequality, {_subs.variable(), term}, _result, _accordingPaper, _conflictingVariables, _solutionSpace ) )
1008 // Create a vector to store the results of each single substitution.
1009 std::vector<CaseDistinction<Poly>> substitutionResultsVector;
1011 * Let k be the maximum degree of x in f, then call for every 1<=i<=k substituteNormal with:
1013 * f^0(x)=0 and ... and f^i-1(x)=0 and f^i(x)~0 as constraints and
1014 * [x -> t] as substitution,
1016 * where the relation is ~.
1018 Poly deriv = Poly( _cons.lhs() );
1019 while( deriv.has( _subs.variable() ) )
1021 // Change the relation symbol of the last added constraint to "=".
1022 Constraint<Poly> equation = Constraint<Poly>( deriv, Relation::EQ );
1023 // Form the derivate of the left hand side of the last added constraint.
1024 deriv = carl::derivative(deriv, _subs.variable(), 1);
1025 // Add the constraint f^i(x)~0.
1026 Constraint<Poly> inequality = Constraint<Poly>( deriv, _relation );
1027 // Apply the substitution (without epsilon) to the new constraints.
1028 substitutionResultsVector.emplace_back();
1029 if( !substituteNormal( equation, {_subs.variable(), term}, substitutionResultsVector.back(), _accordingPaper, _conflictingVariables, _solutionSpace ) )
1031 substitutionResultsVector.emplace_back();
1032 if( !substituteNormal( inequality, {_subs.variable(), term}, substitutionResultsVector.back(), _accordingPaper, _conflictingVariables, _solutionSpace ) )
1034 if( !combine( substitutionResultsVector, _result ) )
1036 simplify( _result, _conflictingVariables, _solutionSpace );
1037 // Remove the last substitution result.
1038 substitutionResultsVector.pop_back();
1043 template<typename Poly>
1044 void substituteInf( const Constraint<Poly>& _cons, const Substitution<Poly>& _subs, CaseDistinction<Poly>& _result, Variables& _conflictingVariables, const detail::EvalDoubleIntervalMap& _solutionSpace )
1046 auto vars = variables(_cons);
1049 if( vars.has( _subs.variable() ) )
1051 if( _cons.relation() == Relation::EQ )
1052 substituteTrivialCase( _cons, _subs, _result );
1053 else if( _cons.relation() == Relation::NEQ )
1054 substituteNotTrivialCase( _cons, _subs, _result );
1057 substituteInfLessGreater( _cons, _subs, _result );
1058 simplify( _result, _conflictingVariables, _solutionSpace );
1062 _result.emplace_back();
1063 _result.back().push_back( _cons );
1067 std::cout << "Warning in substituteInf: The chosen constraint has no variable" << std::endl;
1070 template<typename Poly>
1071 void substituteInfLessGreater( const Constraint<Poly>& _cons, const Substitution<Poly>& _subs, CaseDistinction<Poly>& _result )
1073 assert( _cons.relation() != Relation::EQ );
1074 assert( _cons.relation() != Relation::NEQ );
1075 // Determine the relation for the coefficients of the odd and even degrees.
1076 Relation oddRelationType = Relation::GREATER;
1077 Relation evenRelationType = Relation::LESS;
1078 if( _subs.term().is_minus_infty())
1080 if( _cons.relation() == Relation::GREATER || _cons.relation() == Relation::GEQ )
1082 oddRelationType = Relation::LESS;
1083 evenRelationType = Relation::GREATER;
1088 assert( _subs.term().is_plus_infty() );
1089 if( _cons.relation() == Relation::LESS || _cons.relation() == Relation::LEQ )
1091 oddRelationType = Relation::LESS;
1092 evenRelationType = Relation::GREATER;
1095 // Check all cases according to the substitution rules.
1096 carl::uint varDegree = _cons.maxDegree( _subs.variable() );
1097 assert( varDegree > 0 );
1098 for( carl::uint i = varDegree + 1; i > 0; --i )
1100 // Add conjunction (a_n=0 and ... and a_i~0) to the substitution result.
1101 _result.emplace_back();
1102 for( carl::uint j = varDegree; j > i - 1; --j )
1103 _result.back().push_back( Constraint<Poly>( _cons.coefficient( _subs.variable(), j ), Relation::EQ ) );
1106 if( fmod( i - 1, 2.0 ) != 0.0 )
1107 _result.back().push_back( Constraint<Poly>( _cons.coefficient( _subs.variable(), i - 1 ), oddRelationType ) );
1109 _result.back().push_back( Constraint<Poly>( _cons.coefficient( _subs.variable(), i - 1 ), evenRelationType ) );
1112 _result.back().push_back( Constraint<Poly>( _cons.coefficient( _subs.variable(), i - 1 ), _cons.relation() ) );
1116 template<typename Poly>
1117 void substituteTrivialCase( const Constraint<Poly>& _cons, const Substitution<Poly>& _subs, CaseDistinction<Poly>& _result )
1119 assert( _cons.relation() == Relation::EQ || _cons.relation() == Relation::LEQ || _cons.relation() == Relation::GEQ );
1120 carl::uint varDegree = _cons.maxDegree( _subs.variable() );
1121 // Check the cases (a_0=0 and ... and a_n=0)
1122 _result.emplace_back();
1123 for( carl::uint i = 0; i <= varDegree; ++i )
1124 _result.back().push_back( Constraint<Poly>( _cons.coefficient( _subs.variable(), i ), Relation::EQ ) );
1127 template<typename Poly>
1128 void substituteNotTrivialCase( const Constraint<Poly>& _cons, const Substitution<Poly>& _subs, CaseDistinction<Poly>& _result )
1130 assert( _cons.relation() == Relation::NEQ );
1131 carl::uint varDegree = _cons.maxDegree( _subs.variable() );
1132 for( carl::uint i = 0; i <= varDegree; ++i )
1134 // Add conjunction (a_i!=0) to the substitution result.
1135 _result.emplace_back();
1136 _result.back().push_back( Constraint<Poly>( _cons.coefficient( _subs.variable(), i ), Relation::NEQ ) );
1139 } // end namspace vs