@@ -631,8 +631,6 @@ class Convert1ExpC : public MCKeeper<MCType> {
631
631
bool valid_ {false };
632
632
};
633
633
634
- // / LHS of ax >= by * exp( cz / by )
635
- using LhsTraits = SubexprTraits<1 >;
636
634
// / RHS
637
635
using RhsTraits = SubexprTraits<2 >;
638
636
@@ -651,30 +649,20 @@ class Convert1ExpC : public MCKeeper<MCType> {
651
649
if (1 == body.GetQPTerms ().size ()) {
652
650
const auto & lt = body.GetLinTerms (); // But we have c0*x + c1*y*zz <=> 0
653
651
const auto & qt = body.GetQPTerms ();
654
- LhsTraits lhst;
655
- if (0.0 == std::fabs (rhs) && // rhs==0:
656
- 1 == lt.size ()) // ax >= by exp(cz / by) ?
657
- lhst = ClassifyLhs (lt.coef (0 )*sens, lt.var (0 ));
658
- else if (0 == lt.size ()) // const >= by exp(cz / by) ?
659
- lhst = ClassifyLhs (-rhs*sens, -1 );
660
-
661
- if (lhst) {
662
- if (auto rhst = ClassifyRhsQuadr (
663
- -qt.coef (0 )*sens, qt.var1 (0 ), qt.var2 (0 )))
664
- return AddExpCone (lhst, rhst);
665
- else if (auto rhst = ClassifyRhsQuadr (
666
- -qt.coef (0 )*sens, qt.var2 (0 ), qt.var1 (0 )))
667
- return AddExpCone (lhst, rhst);
668
- }
652
+
653
+ if (auto rhst = ClassifyRhsQuadr (
654
+ -qt.coef (0 )*sens, qt.var1 (0 ), qt.var2 (0 )))
655
+ return AddExpCone (lt, -rhs, -1 , sens, rhst);
656
+ else if (auto rhst = ClassifyRhsQuadr (
657
+ -qt.coef (0 )*sens, qt.var2 (0 ), qt.var1 (0 )))
658
+ return AddExpCone (lt, -rhs, -1 , sens, rhst);
669
659
}
670
660
return false ;
671
661
}
672
662
673
663
// / DoRun.
674
- // / Body: linear, i.e., var1 (or const) >= var2 (or const).
675
- // / In particular, the following cases.
676
- // / ///
677
- // / Considering const>=0.
664
+ // / Body: linear, ax >= b exp(cz / b)
665
+ // /
678
666
// / Accept non-(+-1) coefficients.
679
667
// /
680
668
// / @param body: linear constraint body.
@@ -685,40 +673,17 @@ class Convert1ExpC : public MCKeeper<MCType> {
685
673
bool DoRun (const LinTerms& lt,
686
674
int sens, double rhs) {
687
675
assert ((sens==1 || sens==-1 ) && " sens 1 or -1 only" );
688
- if (0.0 == std::fabs (rhs) && // rhs==0: y==const
689
- 2 == lt.size ()) { // ax >= b exp(cz / b)
690
- if (auto rhst = ClassifyRhsLin (-lt.coef (0 )*sens, lt.var (0 ))) {
691
- // c2*x >= -c1*exp()
692
- if (auto lhst = ClassifyLhs (lt.coef (1 )*sens, lt.var (1 ))) {
693
- return AddExpCone (lhst, rhst);
694
- }
695
- } else if (auto rhst = ClassifyRhsLin (-lt.coef (1 )*sens, lt.var (1 ))) {
696
- // c1*x >= -c2*exp()
697
- if (auto lhst = ClassifyLhs (lt.coef (0 )*sens, lt.var (0 ))) {
698
- return AddExpCone (lhst, rhst);
699
- }
700
- }
701
- } else if (1 == lt.size ()) { // const >= b exp(cz / b)
702
- if (auto lhst = ClassifyLhs (-rhs*sens, -1 )) {
703
- if (auto rhst = ClassifyRhsLin (-lt.coef (0 )*sens, lt.var (0 ))) {
704
- return AddExpCone (lhst, rhst);
705
- }
676
+ for (size_t i=0 ; i<lt.size (); ++i) {
677
+ if (auto rhst = ClassifyRhsLin (-lt.coef (i)*sens, lt.var (i))) {
678
+ // ... >= -c[i]*exp(...)
679
+ return AddExpCone (lt, -rhs, i, sens, rhst);
706
680
}
707
681
}
708
682
return false ;
709
683
}
710
684
711
685
712
686
protected:
713
- LhsTraits ClassifyLhs (double a, int x) {
714
- LhsTraits result {{a}, {x}};
715
- if ((x<0 && a>=0.0 ) || // Lhs is const, >=0
716
- (x>=0 && a>=0.0 && MC ().lb (x)>=0.0 ) || // c*v >= 0
717
- (x>=0 && a<=0.0 && MC ().ub (x)>=0.0 ))
718
- result.valid_ = true ;
719
- return result;
720
- }
721
-
722
687
// / The RHS is just b * (v=exp(z))?
723
688
RhsTraits ClassifyRhsLin (double b, int v) {
724
689
assert (v>=0 );
@@ -758,7 +723,7 @@ class Convert1ExpC : public MCKeeper<MCType> {
758
723
const auto & ae = pConLin->GetAffineExpr ();
759
724
if (0.0 == std::fabs (ae.constant_term () &&
760
725
1 ==ae.GetBody ().size ())) {
761
- const auto & body = ae.GetBody (); // can we ever get here?
726
+ const auto & body = ae.GetBody (); // tested by expcones_06.mod
762
727
if (y == body.var (0 )) { // v2 = z / (c1*y)
763
728
result.coefs_ = {b, b/body.coef (0 )};
764
729
result.vars_ = {y, z};
@@ -773,21 +738,46 @@ class Convert1ExpC : public MCKeeper<MCType> {
773
738
return result;
774
739
}
775
740
776
- bool AddExpCone (LhsTraits l, RhsTraits r) {
777
- assert (l.vars2del_ .empty ());
741
+ // / LHS: sens * (lt+cterm [no lt_i_skip element])
742
+ bool AddExpCone (const LinTerms& lt, double cterm,
743
+ int lt_i_skip, int sens,
744
+ RhsTraits r) {
778
745
for (auto v2d: r.vars2del_ ) // unuse result vars
779
746
MC ().DecrementVarUsage (v2d);
780
747
std::array<int , 3 > args
781
- {l.vars_ [0 ], r.vars_ [0 ], r.vars_ [1 ]};
748
+ {0 , r.vars_ [0 ], r.vars_ [1 ]};
749
+ std::array<double , 3 > coefs
750
+ {1.0 *sens, r.coefs_ [0 ], r.coefs_ [1 ]};
751
+ auto n_lterms = lt.size () - (lt_i_skip>=0 );
752
+ if (0 ==n_lterms) { // LHS = const
753
+ args[0 ] = -1 ; // to be replaced by fixed var==1
754
+ coefs[0 ] = cterm * sens;
755
+ } else if (1 ==n_lterms && 0.0 ==std::fabs (cterm)) {
756
+ for (size_t i=0 ; i<lt.size (); ++i) { // LHS = c * x
757
+ if ((int )i!=lt_i_skip) {
758
+ args[0 ] = lt.var (i);
759
+ coefs[0 ] = lt.coef (i) * sens; // * sens
760
+ }
761
+ }
762
+ } else { // LHS = affine_expr
763
+ AffineExpr ae; // all 3 cases tested by
764
+ ae.constant_term (cterm); // expcones_..mod
765
+ ae.reserve (n_lterms);
766
+ for (size_t i=0 ; i<lt.size (); ++i) {
767
+ if ((int )i!=lt_i_skip)
768
+ ae.add_term ( lt.coef (i), lt.var (i) );
769
+ }
770
+ args[0 ] = MC ().AssignResultVar2Args (
771
+ LinearFunctionalConstraint (std::move (ae)));
772
+ coefs[0 ] = sens; // * sens
773
+ }
782
774
for (int i=0 ; i<3 ; ++i) {
783
775
if (args[i]<0 ) { // marked as -1?
784
776
args[i] = MC ().MakeFixedVar (1.0 );
785
777
}
786
778
}
787
779
MC ().AddConstraint (
788
- ExponentialConeConstraint (
789
- args,
790
- {l.coefs_ [0 ], r.coefs_ [0 ], r.coefs_ [1 ]}));
780
+ ExponentialConeConstraint (args, coefs));
791
781
return true ;
792
782
}
793
783
0 commit comments