From 3207bbd7a63b642ed8f1ea810a4dc20afe171821 Mon Sep 17 00:00:00 2001 From: Sukrit Kalra Date: Sat, 23 Sep 2023 11:14:19 -0700 Subject: [PATCH] Fix rough edges in SolverModel. --- schedulers/tetrisched/CMakeLists.txt | 6 ++- .../include/tetrisched/Expression.hpp | 21 ++++++-- .../include/tetrisched/Partition.hpp | 2 +- .../include/tetrisched/SolverModel.hpp | 52 +++++++++++-------- .../tetrisched/include/tetrisched/Task.hpp | 3 +- .../tetrisched/include/tetrisched/Types.hpp | 12 ++++- .../tetrisched/include/tetrisched/Worker.hpp | 3 +- schedulers/tetrisched/src/Expression.cpp | 1 + schedulers/tetrisched/src/SolverModel.cpp | 19 +++++-- schedulers/tetrisched/test/test_solver.cpp | 10 ++-- 10 files changed, 87 insertions(+), 42 deletions(-) diff --git a/schedulers/tetrisched/CMakeLists.txt b/schedulers/tetrisched/CMakeLists.txt index 4fc8a69f..e7f551f1 100644 --- a/schedulers/tetrisched/CMakeLists.txt +++ b/schedulers/tetrisched/CMakeLists.txt @@ -1,9 +1,11 @@ cmake_minimum_required(VERSION 3.5...3.26) project(tetrisched LANGUAGES CXX) -# GoogleTest requires at least C++14 -set(CMAKE_CXX_STANDARD 14) +# Compile with atleast C++20. +# Set cmake -D CMAKE_CXX_COMPILER=/path/to/C++20/compatible/compiler. +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++2a") # Include debug information. set(CMAKE_BUILD_TYPE Debug) diff --git a/schedulers/tetrisched/include/tetrisched/Expression.hpp b/schedulers/tetrisched/include/tetrisched/Expression.hpp index afd9489a..60e70efd 100644 --- a/schedulers/tetrisched/include/tetrisched/Expression.hpp +++ b/schedulers/tetrisched/include/tetrisched/Expression.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "tetrisched/Partition.hpp" #include "tetrisched/SolverModel.hpp" @@ -12,6 +13,12 @@ namespace tetrisched { +/// A `UtilityFn` represents the function that is used to calculate the utility +/// of a particular expression. +template +using UtilityFnT = std::function; +using UtilityFn = UtilityFnT; + /// A `ParseResultType` enumeration represents the types of results that /// parsing an expression can return. enum ParseResultType { @@ -30,14 +37,21 @@ enum ParseResultType { /// A `ParseResult` class represents the result of parsing an expression. struct ParseResult { + using TimeOrVariableT = std::variant; + using IndicatorT = std::variant; /// The type of the result. ParseResultType type; /// The start time associated with the parsed result. /// Can be either a Time known at runtime or a pointer to a Solver variable. - std::optional> startTime; + std::optional startTime; /// The end time associated with the parsed result. /// Can be either a Time known at runtime or a pointer to a Solver variable. - std::optional> endTime; + std::optional endTime; + /// The indicator associated with the parsed result. + /// This indicator denotes if the expression was satisfied or not. + /// The indicator can return an integer if it is trivially satisfied during parsing. + /// Note that the startTime and endTime are only valid if the indicator is 1. + std::optional indicator; }; struct PartitionTimePairHasher { @@ -65,7 +79,8 @@ class CapacityConstraintMap { CapacityConstraintMap() {} void registerUsageAtTime(const Partition& partition, Time time, VariablePtr variable); - void registerUsageAtTime(const Partition& partition, Time time, uint32_t usage); + void registerUsageAtTime(const Partition& partition, Time time, + uint32_t usage); void registerUsageForDuration(const Partition& partition, Time startTime, Time duration, VariablePtr variable, Time granularity = 1); diff --git a/schedulers/tetrisched/include/tetrisched/Partition.hpp b/schedulers/tetrisched/include/tetrisched/Partition.hpp index 99f659cd..a78cb9d3 100644 --- a/schedulers/tetrisched/include/tetrisched/Partition.hpp +++ b/schedulers/tetrisched/include/tetrisched/Partition.hpp @@ -45,7 +45,7 @@ class Partition { /// Partitions are being allowed to be constructed once and shared by /// multiple Expressions. This allows equivalence checks that currently /// rely on the ID of the Partition instead of the actual Workers inside it. -typedef std::shared_ptr PartitionPtr; +using PartitionPtr = std::shared_ptr; /// @brief A Partitions object represents a collection of Partition. diff --git a/schedulers/tetrisched/include/tetrisched/SolverModel.hpp b/schedulers/tetrisched/include/tetrisched/SolverModel.hpp index 07474e62..aee47032 100644 --- a/schedulers/tetrisched/include/tetrisched/SolverModel.hpp +++ b/schedulers/tetrisched/include/tetrisched/SolverModel.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "tetrisched/Types.hpp" @@ -13,11 +14,8 @@ namespace tetrisched { /// A `VariableType` enumeration represents the types of variable that we allow /// the user to construct. These map to the types of variables that the /// underlying solver supports. -typedef enum VariableType { - VAR_CONTINUOUS, - VAR_INTEGER, - VAR_INDICATOR -} VariableType; +enum VariableType { VAR_CONTINUOUS, VAR_INTEGER, VAR_INDICATOR }; +using VariableType = enum VariableType; /// A `VariableT` class represents a variable in the solver model. Note that /// this is an internal representation of a VariableT and does not contain an @@ -67,21 +65,22 @@ class VariableT { }; // Specialize the VariableT class for Integer type. -template class VariableT; -typedef VariableT Variable; -typedef std::shared_ptr VariablePtr; +template class VariableT; +using Variable = VariableT; +using VariablePtr = std::shared_ptr; /// A `ConstraintType` enumeration represents the types of constraints that we /// allow the user to construct. These map to the types of constraints that the /// underlying solver supports. -typedef enum ConstraintType { +enum ConstraintType { /// LHS <= RHS CONSTR_LE, /// LHS = RHS CONSTR_EQ, /// LHS >= RHS CONSTR_GE, -} ConstraintType; +}; +using ConstraintType = enum ConstraintType; template class ConstraintT { @@ -98,7 +97,8 @@ class ConstraintT { public: /// Generate a new constraint with the given type and right hand side. - ConstraintT(std::string constraintName, ConstraintType constraintType, T rightHandSide); + ConstraintT(std::string constraintName, ConstraintType constraintType, + T rightHandSide); /// Adds a term to the left-hand side constraint. void addTerm(std::pair>> term); @@ -112,23 +112,27 @@ class ConstraintT { /// Retrieve a string representation of this Constraint. std::string toString() const; + /// Retrieve the name of this Constraint. + std::string getName() const; + /// Retrieve the number of terms in this Constraint. size_t size() const; }; // Specialize the Constraint class for Integer. -template class ConstraintT; -typedef ConstraintT Constraint; -typedef std::unique_ptr ConstraintPtr; +template class ConstraintT; +using Constraint = ConstraintT; +using ConstraintPtr = std::unique_ptr; /// A `ObjectiveType` enumeration represents the types of objective functions /// that we allow the user to construct. -typedef enum ObjectiveType { +enum ObjectiveType { /// Maximize the objective function. OBJ_MAXIMIZE, /// Minimize the objective function. OBJ_MINIMIZE, -} ObjectiveType; +}; +using ObjectiveType = enum ObjectiveType; template class ObjectiveFunctionT { @@ -153,9 +157,9 @@ class ObjectiveFunctionT { }; // Specialize the ObjectiveFunction class for Integer. -template class ObjectiveFunctionT; -typedef ObjectiveFunctionT ObjectiveFunction; -typedef std::unique_ptr ObjectiveFunctionPtr; +template class ObjectiveFunctionT; +using ObjectiveFunction = ObjectiveFunctionT; +using ObjectiveFunctionPtr = std::unique_ptr; template class SolverModelT { @@ -187,6 +191,9 @@ class SolverModelT { /// Retrieve a string representation of this SolverModel. std::string toString() const; + /// Export the string representation of this SolverModel to a file. + void exportModel(std::string filename) const; + /// Retrieve the number of variables in this SolverModel. size_t numVariables() const; @@ -200,10 +207,9 @@ class SolverModelT { }; // Specialize the SolverModel class for Integer. -template class SolverModelT; -typedef SolverModelT SolverModel; -typedef std::shared_ptr SolverModelPtr; +template class SolverModelT; +using SolverModel = SolverModelT; +using SolverModelPtr = std::shared_ptr; } // namespace tetrisched - #endif diff --git a/schedulers/tetrisched/include/tetrisched/Task.hpp b/schedulers/tetrisched/include/tetrisched/Task.hpp index 2ad6c9ab..56d7a7d8 100644 --- a/schedulers/tetrisched/include/tetrisched/Task.hpp +++ b/schedulers/tetrisched/include/tetrisched/Task.hpp @@ -17,7 +17,6 @@ class Task { const std::string& getTaskName() const { return taskName; } }; - -typedef std::shared_ptr TaskPtr; +using TaskPtr = std::shared_ptr; } // namespace tetrisched #endif // _TETRISCHED_TASK_HPP_ diff --git a/schedulers/tetrisched/include/tetrisched/Types.hpp b/schedulers/tetrisched/include/tetrisched/Types.hpp index c8a4ffcf..2cf2ded2 100644 --- a/schedulers/tetrisched/include/tetrisched/Types.hpp +++ b/schedulers/tetrisched/include/tetrisched/Types.hpp @@ -14,6 +14,14 @@ std::cout << x << std::endl; \ } +// Macro for the coefficient and the permissible values for the Variables. +// (Sukrit): It is unknown if the ILP will perform better if the coefficients +// and variables are int32_t or double. This is something that we should +// experiment with. Note that both CPLEX and Gurobi do not like 32-bit floating +// points (due to documented numerical difficulties) so the only permissible +// values for this macro is supposed to be int32_t or double. +#define TETRISCHED_ILP_TYPE int32_t + namespace tetrisched { /// Defines the exceptions that the methods can throw. namespace exceptions { @@ -33,11 +41,11 @@ class ExpressionConstructionException : public std::exception { /// We currently use a uint32_t since it translates well from the simulator. /// When this library is deployed for real use, this might need to change to a /// double. -typedef uint32_t Time; +using Time = uint32_t; /// General forward declarations. class Expression; -typedef std::unique_ptr ExpressionPtr; +using ExpressionPtr = std::unique_ptr; /// Forward declarations for Solver instantiations so that we can declare /// them as friend classes in the model. diff --git a/schedulers/tetrisched/include/tetrisched/Worker.hpp b/schedulers/tetrisched/include/tetrisched/Worker.hpp index d45ee285..4475345b 100644 --- a/schedulers/tetrisched/include/tetrisched/Worker.hpp +++ b/schedulers/tetrisched/include/tetrisched/Worker.hpp @@ -20,7 +20,6 @@ class Worker { const std::string &getWorkerName() const; }; -typedef std::shared_ptr WorkerPtr; - +using WorkerPtr = std::shared_ptr; } // namespace tetrisched #endif diff --git a/schedulers/tetrisched/src/Expression.cpp b/schedulers/tetrisched/src/Expression.cpp index 3981d723..6f090cf7 100644 --- a/schedulers/tetrisched/src/Expression.cpp +++ b/schedulers/tetrisched/src/Expression.cpp @@ -151,6 +151,7 @@ ParseResult ChooseExpression::parse(SolverModelPtr solverModel, .type = ParseResultType::EXPRESSION_UTILITY, .startTime = startTime, .endTime = endTime, + .indicator = isSatisfiedVar, }; } } // namespace tetrisched diff --git a/schedulers/tetrisched/src/SolverModel.cpp b/schedulers/tetrisched/src/SolverModel.cpp index fb18b28c..f35c677c 100644 --- a/schedulers/tetrisched/src/SolverModel.cpp +++ b/schedulers/tetrisched/src/SolverModel.cpp @@ -95,6 +95,11 @@ std::string ConstraintT::toString() const { return constraintString; } +template +std::string ConstraintT::getName() const { + return constraintName; +} + template size_t ConstraintT::size() const { return terms.size(); @@ -164,11 +169,12 @@ template std::string SolverModelT::toString() const { std::string modelString; modelString += objectiveFunction->toString(); - modelString += "\nConstraints: \n"; + modelString += "\n\nConstraints: \n"; for (auto &constraint : constraints) { - modelString += "\t" + constraint->toString() + "\n"; + modelString += + constraint->getName() + ": \t" + constraint->toString() + "\n"; } - modelString += "Variables: "; + modelString += "\nVariables: \n\t"; for (auto &variable : variables) { modelString += variable->toString(); if (&variable != &variables.back()) { @@ -178,6 +184,13 @@ std::string SolverModelT::toString() const { return modelString; } +template +void SolverModelT::exportModel(std::string filename) const { + std::ofstream modelFile(filename); + modelFile << this->toString(); + modelFile.close(); +} + template size_t SolverModelT::numVariables() const { return variables.size(); diff --git a/schedulers/tetrisched/test/test_solver.cpp b/schedulers/tetrisched/test/test_solver.cpp index 671551f6..82d61d30 100644 --- a/schedulers/tetrisched/test/test_solver.cpp +++ b/schedulers/tetrisched/test/test_solver.cpp @@ -1,5 +1,7 @@ #include +#include + #include "tetrisched/Solver.hpp" #include "tetrisched/SolverModel.hpp" @@ -50,10 +52,10 @@ TEST(SolverModelTypes, TestSolverModel) { EXPECT_EQ(solverModel->numVariables(), 1); EXPECT_EQ(solverModel->numConstraints(), 1); - EXPECT_EQ(solverModel->toString(), - "Maximize: (1*intVar)\n" - "Constraints: \n\t(1*intVar) <= 10\n" - "Variables: intVar"); + solverModel->exportModel("test.lp"); + EXPECT_TRUE(std::filesystem::exists("test.lp")) + << "The file test.lp was not created."; + std::filesystem::remove("test.lp"); } TEST(SolverModel, TestCPLEXSolverInitialization) {