Skip to content

Commit

Permalink
Implement CapacityConstraintPurging optimization pass.
Browse files Browse the repository at this point in the history
  • Loading branch information
sukritkalra committed Nov 6, 2023
1 parent 80d60b6 commit cb5d3f0
Show file tree
Hide file tree
Showing 10 changed files with 304 additions and 50 deletions.
27 changes: 22 additions & 5 deletions schedulers/tetrisched/include/tetrisched/CapacityConstraint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,21 @@ struct PartitionTimePairHasher {
/// for a Partition at a particular time.
class CapacityConstraint {
private:
/// The name of this CapacityConstraint.
std::string name;
/// The RHS of this constraint i.e., the quantity of this Partition
/// at this time.
uint32_t quantity;
/// The SolverModel constraint that enforces the resource usage.
ConstraintPtr capacityConstraint;

/// A Map from the ExpressionPtr to the usage of that Expression.
std::unordered_map<ExpressionPtr, XOrVariableT<uint32_t>> usageMap;
/// A vector of the Expression contributing the given usage to Constraint.
std::vector<std::pair<ExpressionPtr, XOrVariableT<uint32_t>>> usageVector;

/// The CapacityConstraintMap is allowed to translate this CapacityConstraint.
void translate(SolverModelPtr solverModel);
friend class CapacityConstraintMap;
friend class CapacityConstraintMapPurgingOptimizationPass;

public:
/// Constructs a new CapacityConstraint for the given Partition
Expand All @@ -35,6 +41,15 @@ class CapacityConstraint {
/// Registers the given usage in this CapacityConstraint.
void registerUsage(const ExpressionPtr expression, uint32_t usage);
void registerUsage(const ExpressionPtr expression, VariablePtr variable);

/// Retrieves the maximum quantity of this CapacityConstraint.
uint32_t getQuantity() const;

/// Retrieves the name for this CapacityConstraint.
std::string getName() const;

/// Deactivates this CapacityConstraint.
void deactivate();
};
using CapacityConstraintPtr = std::shared_ptr<CapacityConstraint>;

Expand All @@ -52,9 +67,7 @@ class CapacityConstraintMap {
/// The default granularity for the capacity constraints.
Time granularity;

/// The ObjectiveExpression is allowed to translate this map.
void translate(SolverModelPtr solverModel);
friend class ObjectiveExpression;
friend class CapacityConstraintMapPurgingOptimizationPass;

public:
/// Initialize a CapacityConstraintMap with the given granularity.
Expand Down Expand Up @@ -96,6 +109,10 @@ class CapacityConstraintMap {
Time duration, uint32_t usage,
std::optional<Time> granularity);

/// Translate the CapacityConstraintMap by moving its constraints
/// to the given model.
void translate(SolverModelPtr solverModel);

/// The number of constraints in this map.
size_t size() const;
};
Expand Down
20 changes: 20 additions & 0 deletions schedulers/tetrisched/include/tetrisched/OptimizationPasses.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ class OptimizationPass {
/// Run the pass on the given STRL expression.
virtual void runPass(ExpressionPtr strlExpression,
CapacityConstraintMap& capacityConstraints) = 0;

// Clean the pass after a run.
virtual void clean() = 0;
};
using OptimizationPassPtr = std::shared_ptr<OptimizationPass>;

Expand All @@ -57,12 +60,26 @@ class CriticalPathOptimizationPass : public OptimizationPass {
/// Run the Critical Path optimization pass on the given STRL expression.
void runPass(ExpressionPtr strlExpression,
CapacityConstraintMap& capacityConstraints) override;

/// Clean the pass data structures.
void clean() override;
};

/// A `CapacityConstraintMapPurgingOptimizationPass` is an optimization pass
/// that aims to remove the capacity constraints that are not needed because
/// they are trivially satisfied by the Expression tree.
class CapacityConstraintMapPurgingOptimizationPass : public OptimizationPass {
private:
/// A Vector of the cliques in the Expression tree.
std::vector<std::unordered_set<std::string>> cliques;

/// Computes the cliques from a bottom-up traversal of the STRL.
void computeCliques(ExpressionPtr expression);

/// Deactivates the CapacityConstraints that are trivially satisfied.
void deactivateCapacityConstraints(
CapacityConstraintMap& capacityConstraints);

public:
/// Instantiate the CapacityConstraintMapPurgingOptimizationPass.
CapacityConstraintMapPurgingOptimizationPass();
Expand All @@ -71,6 +88,9 @@ class CapacityConstraintMapPurgingOptimizationPass : public OptimizationPass {
/// expression.
void runPass(ExpressionPtr strlExpression,
CapacityConstraintMap& capacityConstraints) override;

/// Clean the pass data structures.
void clean() override;
};

class OptimizationPassRunner {
Expand Down
13 changes: 12 additions & 1 deletion schedulers/tetrisched/include/tetrisched/SolverModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class VariableT {

/// Retrieve the ID of this VariableT.
uint32_t getId() const;

/// Retrieve the solution value for this VariableT.
/// If the solution value is not set, then the solver hasn't found a solution
/// (yet).
Expand Down Expand Up @@ -192,6 +192,9 @@ using ConstraintAttribute = enum ConstraintAttribute;
template <typename T>
class ConstraintT {
private:
/// A boolean variable to signify if the constraint is active.
/// If True, the solvers should put it into the model.
bool active;
/// Used to generate unique IDs for each Constraint.
static uint32_t constraintIdCounter;
/// The ID of this constraint.
Expand Down Expand Up @@ -249,6 +252,14 @@ class ConstraintT {
/// Retrieve the number of terms in this Constraint.
size_t size() const;

/// Deactivates this Constraint.
/// Backend solvers may choose to not add this constraint
/// to the model if it is deactivated.
void deactivate();

/// Checks if the constraint is active.
bool isActive() const;

/// Check if the constraint is trivially-satisfiable.
/// A constraint is trivially satisfied if, given the upper and lower bounds
/// on the variables, there is no feasible value for the variables that can
Expand Down
41 changes: 25 additions & 16 deletions schedulers/tetrisched/src/CapacityConstraint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ size_t PartitionTimePairHasher::operator()(

/* Method definitions for CapacityConstraint */
CapacityConstraint::CapacityConstraint(const Partition& partition, Time time)
: capacityConstraint(std::make_shared<Constraint>(
"CapacityConstraint_" + partition.getPartitionName() + "_at_" +
std::to_string(time),
ConstraintType::CONSTR_LE, partition.getQuantity())) {}
: name("CapacityConstraint_" + partition.getPartitionName() + "_at_" +
std::to_string(time)),
quantity(partition.getQuantity()),
capacityConstraint(std::make_shared<Constraint>(
name, ConstraintType::CONSTR_LE, quantity)) {}

void CapacityConstraint::registerUsage(const ExpressionPtr expression,
uint32_t usage) {
Expand All @@ -28,27 +29,35 @@ void CapacityConstraint::registerUsage(const ExpressionPtr expression,
return;
}
capacityConstraint->addTerm(usage);
usageMap[expression] = usage;
usageVector.emplace_back(expression, usage);
}

void CapacityConstraint::registerUsage(const ExpressionPtr expression,
VariablePtr variable) {
capacityConstraint->addTerm(variable);
usageMap[expression] = variable;
usageVector.emplace_back(expression, variable);
}

void CapacityConstraint::translate(SolverModelPtr solverModel) {
if (!capacityConstraint->isTriviallySatisfiable()) {
// COMMENT (Sukrit): We can try to see if adding Lazy constraints
// helps ever. In my initial analysis, this makes the presolve and
// root relaxation less efficient making the overall solver time
// higher. Maybe for too many of the CapacityConstraintMap constraints,
// this will help.
// capacityConstraint->addAttribute(ConstraintAttribute::LAZY_CONSTRAINT);
solverModel->addConstraint(capacityConstraint);
}
solverModel->addConstraint(capacityConstraint);
// if (!capacityConstraint->isTriviallySatisfiable()) {
// // COMMENT (Sukrit): We can try to see if adding Lazy constraints
// // helps ever. In my initial analysis, this makes the presolve and
// // root relaxation less efficient making the overall solver time
// // higher. Maybe for too many of the CapacityConstraintMap constraints,
// // this will help.
// //
// capacityConstraint->addAttribute(ConstraintAttribute::LAZY_CONSTRAINT);
// solverModel->addConstraint(capacityConstraint);
// }
}

void CapacityConstraint::deactivate() { capacityConstraint->deactivate(); }

uint32_t CapacityConstraint::getQuantity() const { return quantity; }

std::string CapacityConstraint::getName() const { return name; }

/* Method definitions for CapacityConstraintMap */

CapacityConstraintMap::CapacityConstraintMap(Time granularity)
Expand Down Expand Up @@ -116,7 +125,7 @@ void CapacityConstraintMap::translate(SolverModelPtr solverModel) {
}

// Clear the map now that the constraints have been drained.
capacityConstraints.clear();
// capacityConstraints.clear();
}

size_t CapacityConstraintMap::size() const {
Expand Down
2 changes: 0 additions & 2 deletions schedulers/tetrisched/src/Expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1299,8 +1299,6 @@ ParseResultPtr MinExpression::parse(SolverModelPtr solverModel,
}
}
} else {
std::cout << "Type of child was: " << childParsedResult->type
<< std::endl;
throw tetrisched::exceptions::ExpressionConstructionException(
"Indicator needed from child-" + std::to_string(i) + "(" +
children[i]->getName() + ") for MIN, but was not present!");
Expand Down
34 changes: 21 additions & 13 deletions schedulers/tetrisched/src/GurobiSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ void GurobiSolver::setParameters(GRBModel& gurobiModel) {
// Ask Gurobi to aggressively cut the search space.
gurobiModel.set(GRB_IntParam_Cuts, 3);

// Ask Gurobi to aggressively presolve the model.
gurobiModel.set(GRB_IntParam_Presolve, 2);
// Ask Gurobi to conservatively presolve the model.
gurobiModel.set(GRB_IntParam_Presolve, 1);

// Ask Gurobi to find new incumbent solutions rather than prove bounds.
gurobiModel.set(GRB_IntParam_MIPFocus, 1);
Expand All @@ -51,28 +51,30 @@ GRBVar GurobiSolver::translateVariable(GRBModel& gurobiModel,
double upperBound = variable->upperBound.has_value()
? variable->upperBound.value()
: GRB_INFINITY;
GRBVar var;
GRBVar var;
switch (variable->variableType) {
case VariableType::VAR_INTEGER:
var = gurobiModel.addVar(lowerBound, upperBound, 0.0, GRB_INTEGER,
variable->variableName);
break;
variable->variableName);
break;
case VariableType::VAR_CONTINUOUS:
var = gurobiModel.addVar(lowerBound, upperBound, 0.0, GRB_CONTINUOUS,
variable->variableName);
variable->variableName);
break;
case VariableType::VAR_INDICATOR:
var = gurobiModel.addVar(lowerBound, upperBound, 0.0, GRB_BINARY,
variable->variableName);
variable->variableName);
break;
default:
throw tetrisched::exceptions::SolverException(
"Invalid variable type: " + std::to_string(variable->variableType));
}
// Give the Gurobi variable an initial solution value if it is available.
if (variable->initialValue.has_value()) {
var.set(GRB_DoubleAttr_Start, variable->initialValue.value());
TETRISCHED_DEBUG("Setting start value of variable " << variable->getName() << "(" << variable->getId() << ") to " << variable->initialValue.value());
var.set(GRB_DoubleAttr_Start, variable->initialValue.value());
TETRISCHED_DEBUG("Setting start value of variable "
<< variable->getName() << "(" << variable->getId()
<< ") to " << variable->initialValue.value());
}
return var;
}
Expand Down Expand Up @@ -176,10 +178,16 @@ void GurobiSolver::translateModel() {

// Generate all the constraints.
for (const auto& [constraintId, constraint] : solverModel->constraints) {
TETRISCHED_DEBUG("Adding Constraint " << constraint->getName() << "("
<< constraintId
<< ") to Gurobi Model.");
auto _ = translateConstraint(*gurobiModel, constraint);
if (constraint->isActive()) {
TETRISCHED_DEBUG("Adding active Constraint " << constraint->getName()
<< "(" << constraintId
<< ") to Gurobi Model.");
auto _ = translateConstraint(*gurobiModel, constraint);
} else {
TETRISCHED_DEBUG("Skipping the addition of inactive Constraint "
<< constraint->getName() << "(" << constraintId
<< ") to Gurobi Model.");
}
}

// Translate the objective function.
Expand Down
Loading

0 comments on commit cb5d3f0

Please sign in to comment.