| 460 | } |
| 461 | |
| 462 | void MILPEncoder::encodeSigmoidConstraint( GurobiWrapper &gurobi, SigmoidConstraint *sigmoid ) |
| 463 | { |
| 464 | unsigned sourceVariable = sigmoid->getB(); // x_b |
| 465 | unsigned targetVariable = sigmoid->getF(); // x_f |
| 466 | double sourceLb = _tableau.getLowerBound( sourceVariable ); |
| 467 | double sourceUb = _tableau.getUpperBound( sourceVariable ); |
| 468 | |
| 469 | if ( sourceLb == sourceUb ) |
| 470 | { |
| 471 | return; |
| 472 | } |
| 473 | else if ( FloatUtils::lt( sourceLb, 0 ) && FloatUtils::gt( sourceUb, 0 ) ) |
| 474 | { |
| 475 | List<GurobiWrapper::Term> terms; |
| 476 | String binVarName = Stringf( "a%u", _binVarIndex ); // a = 1 -> the case where x_b >= 0, |
| 477 | // otherwise where x_b <= 0 |
| 478 | gurobi.addVariable( binVarName, 0, 1, GurobiWrapper::BINARY ); |
| 479 | |
| 480 | // Constraint where x_b >= 0 |
| 481 | // Upper line is tangent and lower line is secant for an overapproximation with a |
| 482 | // linearization. |
| 483 | |
| 484 | int binVal = 1; |
| 485 | |
| 486 | // tangent line: x_f = tangentSlope * (x_b - tangentPoint) + yAtTangentPoint |
| 487 | double tangentPoint = sourceUb / 2; |
| 488 | double yAtTangentPoint = sigmoid->sigmoid( tangentPoint ); |
| 489 | double tangentSlope = sigmoid->sigmoidDerivative( tangentPoint ); |
| 490 | terms.append( GurobiWrapper::Term( 1, Stringf( "x%u", targetVariable ) ) ); |
| 491 | terms.append( GurobiWrapper::Term( -tangentSlope, Stringf( "x%u", sourceVariable ) ) ); |
| 492 | gurobi.addLeqIndicatorConstraint( |
| 493 | binVarName, binVal, terms, -tangentSlope * tangentPoint + yAtTangentPoint ); |
| 494 | terms.clear(); |
| 495 | |
| 496 | // secant line: x_f = secantSlope * (x_b - 0) + y_l |
| 497 | double y_l = sigmoid->sigmoid( 0 ); |
| 498 | double y_u = sigmoid->sigmoid( sourceUb ); |
| 499 | double secantSlope = ( y_u - y_l ) / sourceUb; |
| 500 | terms.append( GurobiWrapper::Term( 1, Stringf( "x%u", targetVariable ) ) ); |
| 501 | terms.append( GurobiWrapper::Term( -secantSlope, Stringf( "x%u", sourceVariable ) ) ); |
| 502 | gurobi.addGeqIndicatorConstraint( binVarName, binVal, terms, y_l ); |
| 503 | terms.clear(); |
| 504 | |
| 505 | // lower bound of x_b |
| 506 | terms.append( GurobiWrapper::Term( 1, Stringf( "x%u", sourceVariable ) ) ); |
| 507 | gurobi.addGeqIndicatorConstraint( binVarName, binVal, terms, 0 ); |
| 508 | terms.clear(); |
| 509 | |
| 510 | // lower bound of x_f |
| 511 | terms.append( GurobiWrapper::Term( 1, Stringf( "x%u", targetVariable ) ) ); |
| 512 | gurobi.addGeqIndicatorConstraint( binVarName, binVal, terms, y_l ); |
| 513 | terms.clear(); |
| 514 | |
| 515 | // Constraints where x_b <= 0 |
| 516 | // Upper line is secant and lower line is tangent for an overapproximation with a |
| 517 | // linearization. |
| 518 | |
| 519 | binVal = 0; |
nothing calls this directly
no test coverage detected