From eb7579bdb943dff1e9b9a18c1163c6230f0808bd Mon Sep 17 00:00:00 2001 From: Sukrit Kalra Date: Sun, 31 Dec 2023 14:44:21 -0800 Subject: [PATCH] Add variant of ScaleExpression that amplifies indicators of children. --- .../include/tetrisched/Expression.hpp | 8 + .../include/tetrisched/SolverModel.hpp | 1 + schedulers/tetrisched/python/Expressions.cpp | 16 +- .../python/stubs/tetrisched_py/strl.pyi | 16 +- schedulers/tetrisched/src/Expression.cpp | 297 ++++++++++-------- schedulers/tetrisched/src/SolverModel.cpp | 10 + 6 files changed, 208 insertions(+), 140 deletions(-) diff --git a/schedulers/tetrisched/include/tetrisched/Expression.hpp b/schedulers/tetrisched/include/tetrisched/Expression.hpp index 44283a8c..01816b64 100644 --- a/schedulers/tetrisched/include/tetrisched/Expression.hpp +++ b/schedulers/tetrisched/include/tetrisched/Expression.hpp @@ -489,12 +489,20 @@ class MaxExpression : public Expression { }; /// A `ScaleExpression` amplifies the utility of its child by a scalar factor. +/// It can also be used to disregard the utility and amplify the indicator of +/// the child expression by the scalar factor. class ScaleExpression : public Expression { private: /// The scalar factor to amplify the utility of the child by. TETRISCHED_ILP_TYPE scaleFactor; + /// A boolean indicating if the utility should be disregarded. + /// Instead, the indicator of the child expression is amplified by the + /// scalar factor. + bool disregardUtility; public: + ScaleExpression(std::string name, TETRISCHED_ILP_TYPE scaleFactor, + bool disregardUtility); ScaleExpression(std::string name, TETRISCHED_ILP_TYPE scaleFactor); void addChild(ExpressionPtr child) override; ParseResultPtr parse(SolverModelPtr solverModel, diff --git a/schedulers/tetrisched/include/tetrisched/SolverModel.hpp b/schedulers/tetrisched/include/tetrisched/SolverModel.hpp index 31824267..5f739136 100644 --- a/schedulers/tetrisched/include/tetrisched/SolverModel.hpp +++ b/schedulers/tetrisched/include/tetrisched/SolverModel.hpp @@ -335,6 +335,7 @@ class ObjectiveFunctionT { ObjectiveFunctionT(ObjectiveType objectiveType); /// Adds a term to the left-hand side constraint. + void addTerm(T coefficient, const XOrVariableT& term); void addTerm(T coefficient, std::shared_ptr> variable); void addTerm(T constant); diff --git a/schedulers/tetrisched/python/Expressions.cpp b/schedulers/tetrisched/python/Expressions.cpp index 65f49fba..e82b853b 100644 --- a/schedulers/tetrisched/python/Expressions.cpp +++ b/schedulers/tetrisched/python/Expressions.cpp @@ -286,9 +286,21 @@ void defineSTRLExpressions(py::module_& tetrisched_m) { "scaling factor.\n" "\nArgs:\n" " name (str): The name of the ScaleExpression.\n" - " scalingFactor (TETRISCHED_ILP_TYPE): The scaling factor of the " + " scaleFactor (TETRISCHED_ILP_TYPE): The scaling factor of the " "ScaleExpression.", - py::arg("name"), py::arg("scalingFactor")); + py::arg("name"), py::arg("scaleFactor")) + .def(py::init(), + "Initializes a ScaleExpression with the given name and " + "scaling factor.\n" + "\nArgs:\n" + " name (str): The name of the ScaleExpression.\n" + " scaleFactor (TETRISCHED_ILP_TYPE): The scaling factor of " + "the ScaleExpression.\n" + " disregardUtility (bool): If true, the utility of the child " + "expression is disregarded, \nand its indicator is amplified by the " + "scale factor instead.", + py::arg("name"), py::arg("scaleFactor"), + py::arg("disregardUtility")); // Define the LessThanExpression. py::class_ None: + @typing.overload + def __init__(self, name: str, scaleFactor: float) -> None: + """ + Initializes a ScaleExpression with the given name and scaling factor. + + Args: + name (str): The name of the ScaleExpression. + scaleFactor (TETRISCHED_ILP_TYPE): The scaling factor of the ScaleExpression. + """ + @typing.overload + def __init__(self, name: str, scaleFactor: float, disregardUtility: bool) -> None: """ Initializes a ScaleExpression with the given name and scaling factor. Args: name (str): The name of the ScaleExpression. - scalingFactor (TETRISCHED_ILP_TYPE): The scaling factor of the ScaleExpression. + scaleFactor (TETRISCHED_ILP_TYPE): The scaling factor of the ScaleExpression. + disregardUtility (bool): If true, the utility of the child expression is disregarded, + and its indicator is amplified by the scale factor instead. """ class SolutionResult: diff --git a/schedulers/tetrisched/src/Expression.cpp b/schedulers/tetrisched/src/Expression.cpp index bfc73ca5..883134a8 100644 --- a/schedulers/tetrisched/src/Expression.cpp +++ b/schedulers/tetrisched/src/Expression.cpp @@ -1678,12 +1678,12 @@ ParseResultPtr LessThanExpression::parse( // Parse both the children. // tbb::task_group lessThanExpressionChildParsing; // lessThanExpressionChildParsing.run([&] { - children[0]->parse(solverModel, availablePartitions, capacityConstraints, - currentTime); + children[0]->parse(solverModel, availablePartitions, capacityConstraints, + currentTime); // }); // lessThanExpressionChildParsing.run([&] { - children[1]->parse(solverModel, availablePartitions, capacityConstraints, - currentTime); + children[1]->parse(solverModel, availablePartitions, capacityConstraints, + currentTime); // }); // lessThanExpressionChildParsing.wait(); TETRISCHED_DEBUG( @@ -1912,132 +1912,132 @@ ParseResultPtr MinExpression::parse( for (auto& child : children) { // minChildrenParsing.run([&] { - // Parse the Child. - auto childParsedResult = child->parse(solverModel, availablePartitions, - capacityConstraints, currentTime); + // Parse the Child. + auto childParsedResult = child->parse(solverModel, availablePartitions, + capacityConstraints, currentTime); - if (childParsedResult->type != ParseResultType::EXPRESSION_UTILITY) { - // If any of the children cannot provide a utility, the MIN expression - // cannot be satisfied. - continue; - //return; - } + if (childParsedResult->type != ParseResultType::EXPRESSION_UTILITY) { + // If any of the children cannot provide a utility, the MIN expression + // cannot be satisfied. + continue; + // return; + } - // Ensure that the MIN is satisfied only if this child is satisfied. - if (childParsedResult->indicator.has_value()) { - auto childIndicator = childParsedResult->indicator.value(); - if (childIndicator.isVariable()) { - minIndicatorConstraint->addTerm(childIndicator); - ++numEnforceableChildren; - } else { - auto indicatorValue = childIndicator.get(); - if (indicatorValue == 1) { - // This child is trivially satisifed, we shouldn't add its utility. - TETRISCHED_DEBUG("Child " << child->getName() << " of MIN " << name - << " is trivially satisfied.") - // continue; - } else { - throw tetrisched::exceptions::ExpressionConstructionException( - "Indicator needed from " + child->getName() + - " for MIN, but was 0."); - } - } + // Ensure that the MIN is satisfied only if this child is satisfied. + if (childParsedResult->indicator.has_value()) { + auto childIndicator = childParsedResult->indicator.value(); + if (childIndicator.isVariable()) { + minIndicatorConstraint->addTerm(childIndicator); + ++numEnforceableChildren; } else { - throw tetrisched::exceptions::ExpressionConstructionException( - "Indicator needed from " + child->getName() + - " for MIN, but was not present!"); - } - - // Ensure that the MIN's start time is <= the start time of this child. - ConstraintPtr minStartTimeConstraint = std::make_shared( - name + "_min_start_time_constr_child_" + child->getName(), - ConstraintType::CONSTR_GE, 0, 2); // minStartTime < childStartTime - if (childParsedResult->startTime.has_value()) { - auto childStartTime = childParsedResult->startTime.value(); - if (childStartTime.isVariable()) { - auto childStartTimeVariable = childStartTime.get(); - minStartTimeConstraint->addTerm(1, childStartTimeVariable); - // if (auto lowerBound = childStartTimeVariable->getLowerBound(); - // lowerBound.has_value()) { - // auto lowerBoundValue = lowerBound.value(); - // std::cout << "Lower bound for " << - // childStartTimeVariable->getName() - // << " is " << lowerBoundValue << std::endl; - // if (lowerBoundValue < startTimeRange.first) { - // startTimeRange.first = lowerBoundValue; - // } - // if (lowerBoundValue > startTimeRange.second) { - // startTimeRange.second = lowerBoundValue; - // } - // } + auto indicatorValue = childIndicator.get(); + if (indicatorValue == 1) { + // This child is trivially satisifed, we shouldn't add its utility. + TETRISCHED_DEBUG("Child " << child->getName() << " of MIN " << name + << " is trivially satisfied.") + // continue; } else { - auto childStartTimeValue = childStartTime.get