From 99450cf6b417d913342954b9ea9ec719ef3eaeff Mon Sep 17 00:00:00 2001 From: "Ray (Jui-Tse) Hung" Date: Tue, 31 Oct 2023 19:30:48 -0400 Subject: [PATCH] Tetrisched - Pass in utility to ChooseExpression and MalleableChooseExpression (#62) * Fix tetrisched build error * Allow user to specify utility in ChooseExpression and MalleableChooseExpression constructor * Pass placement_rewards as utility in tetrisched.strl.ChooseExpression in tetrisched_scheduler.py * Update utility type from double to TETRISCHED_ILP_TYPE * Update utility type from double to TETRISCHED_ILP_TYPE --------- Co-authored-by: Sukrit Kalra --- .../include/tetrisched/Expression.hpp | 9 +++-- .../include/tetrisched/Partition.hpp | 1 + schedulers/tetrisched/python/Expressions.cpp | 9 ++--- schedulers/tetrisched/src/Expression.cpp | 25 ++++++++------ .../tetrisched/test/test_expression.cpp | 34 +++++++++---------- schedulers/tetrisched_scheduler.py | 14 +++++++- 6 files changed, 58 insertions(+), 34 deletions(-) diff --git a/schedulers/tetrisched/include/tetrisched/Expression.hpp b/schedulers/tetrisched/include/tetrisched/Expression.hpp index 2f091c97..aac2209f 100644 --- a/schedulers/tetrisched/include/tetrisched/Expression.hpp +++ b/schedulers/tetrisched/include/tetrisched/Expression.hpp @@ -330,13 +330,16 @@ class ChooseExpression : public Expression { Time duration; /// The end time of the choice represented by this Expression. Time endTime; + // The utility of the choice represented by this Expression. + TETRISCHED_ILP_TYPE utility; /// The variables that represent the choice of each Partition for this /// Expression. std::unordered_map partitionVariables; public: ChooseExpression(std::string taskName, Partitions resourcePartitions, - uint32_t numRequiredMachines, Time startTime, Time duration); + uint32_t numRequiredMachines, Time startTime, Time duration, + TETRISCHED_ILP_TYPE utility); void addChild(ExpressionPtr child) override; ParseResultPtr parse(SolverModelPtr solverModel, Partitions availablePartitions, @@ -361,6 +364,8 @@ class MalleableChooseExpression : public Expression { Time endTime; /// The granularity at which the rectangle choices are to be made. Time granularity; + // The utility of the choice represented by this Expression. + TETRISCHED_ILP_TYPE utility; /// The variables that represent the choice of machines from each /// Partition at each time corresponding to this Expression. std::unordered_map, VariablePtr, @@ -370,7 +375,7 @@ class MalleableChooseExpression : public Expression { public: MalleableChooseExpression(std::string taskName, Partitions resourcePartitions, uint32_t resourceTimeSlots, Time startTime, - Time endTime, Time granularity); + Time endTime, Time granularity, TETRISCHED_ILP_TYPE utility); void addChild(ExpressionPtr child) override; ParseResultPtr parse(SolverModelPtr solverModel, Partitions availablePartitions, diff --git a/schedulers/tetrisched/include/tetrisched/Partition.hpp b/schedulers/tetrisched/include/tetrisched/Partition.hpp index b3d09753..a29d2010 100644 --- a/schedulers/tetrisched/include/tetrisched/Partition.hpp +++ b/schedulers/tetrisched/include/tetrisched/Partition.hpp @@ -1,5 +1,6 @@ #ifndef _TETRISCHED_PARTITION_HPP_ #define _TETRISCHED_PARTITION_HPP_ +#include #include #include diff --git a/schedulers/tetrisched/python/Expressions.cpp b/schedulers/tetrisched/python/Expressions.cpp index 3cb858a8..fa19e786 100644 --- a/schedulers/tetrisched/python/Expressions.cpp +++ b/schedulers/tetrisched/python/Expressions.cpp @@ -108,10 +108,10 @@ void defineSTRLExpressions(py::module_& tetrisched_m) { "ChooseExpression") .def(py::init([](std::string taskName, tetrisched::Partitions partitions, uint32_t numRequiredMachines, tetrisched::Time startTime, - tetrisched::Time duration) { + tetrisched::Time duration, TETRISCHED_ILP_TYPE utility) { return std::make_shared( taskName, partitions, numRequiredMachines, startTime, - duration); + duration, utility); }), "Initializes a ChooseExpression for the given task to be placed on " "`numRequiredMachines` from the given partition at the given " @@ -123,10 +123,11 @@ void defineSTRLExpressions(py::module_& tetrisched_m) { tetrisched_m, "MalleableChooseExpression") .def(py::init([](std::string taskName, tetrisched::Partitions partitions, uint32_t resourceTimeSlots, tetrisched::Time startTime, - tetrisched::Time endTime, tetrisched::Time granularity) { + tetrisched::Time endTime, tetrisched::Time granularity, + TETRISCHED_ILP_TYPE utility) { return std::make_shared( taskName, partitions, resourceTimeSlots, startTime, endTime, - granularity); + granularity, utility); }), "Initializes a MalleableChooseExpression for the given task to be " "placed on the given partitions at the given startTime, " diff --git a/schedulers/tetrisched/src/Expression.cpp b/schedulers/tetrisched/src/Expression.cpp index b90ed394..4ca24bf2 100644 --- a/schedulers/tetrisched/src/Expression.cpp +++ b/schedulers/tetrisched/src/Expression.cpp @@ -1,6 +1,7 @@ #include "tetrisched/Expression.hpp" #include +#include #include #include #include @@ -327,13 +328,15 @@ std::string Expression::getDescriptiveName() const { ChooseExpression::ChooseExpression(std::string taskName, Partitions resourcePartitions, uint32_t numRequiredMachines, Time startTime, - Time duration) + Time duration, + TETRISCHED_ILP_TYPE utility) : Expression(taskName, ExpressionType::EXPR_CHOOSE), resourcePartitions(resourcePartitions), numRequiredMachines(numRequiredMachines), startTime(startTime), duration(duration), - endTime(startTime + duration) {} + endTime(startTime + duration), + utility(utility) {} void ChooseExpression::addChild(ExpressionPtr child) { throw tetrisched::exceptions::ExpressionConstructionException( @@ -424,16 +427,16 @@ ParseResultPtr ChooseExpression::parse( solverModel->addConstraint(std::move(fulfillsDemandConstraint)); // Construct the Utility function for this Choose expression. - auto utility = + auto utilityFunction = std::make_shared(ObjectiveType::OBJ_MAXIMIZE); - utility->addTerm(1, isSatisfiedVar); + utilityFunction->addTerm(utility, isSatisfiedVar); // Construct the return value. parsedResult->type = ParseResultType::EXPRESSION_UTILITY; parsedResult->startTime = startTime; parsedResult->endTime = endTime; parsedResult->indicator = isSatisfiedVar; - parsedResult->utility = std::move(utility); + parsedResult->utility = std::move(utilityFunction); return parsedResult; } @@ -476,14 +479,16 @@ std::string ChooseExpression::getDescriptiveName() const { /* Method definitions for GeneralizedChoose */ MalleableChooseExpression::MalleableChooseExpression( std::string taskName, Partitions resourcePartitions, - uint32_t resourceTimeSlots, Time startTime, Time endTime, Time granularity) + uint32_t resourceTimeSlots, Time startTime, Time endTime, Time granularity, + TETRISCHED_ILP_TYPE utility) : Expression(taskName, ExpressionType::EXPR_MALLEABLE_CHOOSE), resourcePartitions(resourcePartitions), resourceTimeSlots(resourceTimeSlots), startTime(startTime), endTime(endTime), granularity(granularity), - partitionVariables() {} + partitionVariables(), + utility(utility) {} void MalleableChooseExpression::addChild(ExpressionPtr child) { throw tetrisched::exceptions::ExpressionConstructionException( @@ -774,16 +779,16 @@ ParseResultPtr MalleableChooseExpression::parse( solverModel->addConstraint(std::move(endTimeConstraint)); // Construct the Utility function for this Choose expression. - auto utility = + auto utilityFunction = std::make_shared(ObjectiveType::OBJ_MAXIMIZE); - utility->addTerm(1, isSatisfiedVar); + utilityFunction->addTerm(utility, isSatisfiedVar); // Construct the return value. parsedResult->type = ParseResultType::EXPRESSION_UTILITY; parsedResult->startTime = startTimeVariable; parsedResult->endTime = endTimeVariable; parsedResult->indicator = isSatisfiedVar; - parsedResult->utility = std::move(utility); + parsedResult->utility = std::move(utilityFunction); return parsedResult; } diff --git a/schedulers/tetrisched/test/test_expression.cpp b/schedulers/tetrisched/test/test_expression.cpp index acc2f5a4..3dd39c25 100644 --- a/schedulers/tetrisched/test/test_expression.cpp +++ b/schedulers/tetrisched/test/test_expression.cpp @@ -12,9 +12,9 @@ TEST(Expression, TestChooseExpressionIsLeaf) { tetrisched::Partitions partitions = tetrisched::Partitions(); auto chooseExpression = std::make_unique( - "task1", partitions, 0, 0, 10); + "task1", partitions, 0, 0, 10, 1); auto chooseExpression2 = std::make_unique( - "task1", partitions, 0, 0, 10); + "task1", partitions, 0, 0, 10, 1); EXPECT_THROW(chooseExpression->addChild(std::move(chooseExpression2)), tetrisched::exceptions::ExpressionConstructionException); } @@ -23,10 +23,10 @@ TEST(Expression, TestMinExpressionIsNOTLeaf) { tetrisched::Partitions partitions = tetrisched::Partitions(); tetrisched::ExpressionPtr chooseExpression = std::make_shared("task1", partitions, 0, 0, - 10); + 10, 1); tetrisched::ExpressionPtr chooseExpression2 = std::make_shared("task1", partitions, 0, 0, - 10); + 10, 1); tetrisched::ExpressionPtr minExpression = std::make_shared("TEST_MIN"); @@ -44,7 +44,7 @@ TEST(Expression, TestMaxExpressionOnlyAllowsChooseExpressionChildren) { // Ensure ChooseExpression can be added to MaxExpression. tetrisched::ExpressionPtr chooseExpression = std::make_shared("task1", partitions, 0, 0, - 10); + 10, 1); tetrisched::ExpressionPtr maxExpression = std::make_shared("TestMax"); EXPECT_NO_THROW(maxExpression->addChild(chooseExpression)) @@ -70,10 +70,10 @@ TEST(Expression, TestLessThanEnforcesOrdering) { // Construct the choice for the two tasks. tetrisched::ExpressionPtr chooseTask1 = std::make_shared("task1", partitions, 1, 0, - 100); + 100, 1); tetrisched::ExpressionPtr chooseTask2 = std::make_shared("task2", partitions, 1, - 200, 100); + 200, 100, 1); // Construct the LessThan expression. tetrisched::ExpressionPtr lessThanExpression = @@ -151,10 +151,10 @@ TEST(Expression, TestMaxExpressionEnforcesSingleChoice) { // Construct two choices for a task. tetrisched::ExpressionPtr chooseTask1_1 = std::make_shared("task1", partitions, 1, 0, - 100); + 100, 1); tetrisched::ExpressionPtr chooseTask1_2 = std::make_shared("task1", partitions, 1, - 100, 100); + 100, 100, 1); // Constrain only one choice to actually happen. tetrisched::ExpressionPtr maxChooseExpr = @@ -197,10 +197,10 @@ TEST(Expression, TestMinExpressionEnforcesAllChildrenSatisfied) { // Construct two choices for a task. tetrisched::ExpressionPtr chooseTask1_1 = std::make_shared("task1_1", partitions, 1, - 0, 100); + 0, 100, 1); tetrisched::ExpressionPtr chooseTask1_2 = std::make_shared("task1_2", partitions, 1, - 100, 100); + 100, 100, 1); // Constrain both choices to actually happen. tetrisched::ExpressionPtr minChooseExpr = @@ -248,10 +248,10 @@ TEST(Expression, TestMinExpressionEnforcesNoneSatisfied) { // Construct two choices for a task. tetrisched::ExpressionPtr chooseTask1_1 = std::make_shared("task1_1", partitions, 1, - 0, 100); + 0, 100, 1); tetrisched::ExpressionPtr chooseTask1_2 = std::make_shared("task1_2", partitions, 1, - 50, 100); + 50, 100, 1); // Constrain both choices to actually happen. tetrisched::ExpressionPtr minChooseExpr = @@ -296,7 +296,7 @@ TEST(Expression, TestScaleExpressionDoublesUtility) { // Construct the choice for a task. tetrisched::ExpressionPtr chooseExpression = std::make_shared("task1", partitions, 1, 0, - 10); + 10, 1); // Scale the utility by 2. tetrisched::ExpressionPtr scaleExpression = std::make_shared("TEST_SCALE", 4); @@ -345,7 +345,7 @@ TEST(Expression, TestAllocationExpressionFailsChoice) { // Construct the Choice for a second task. tetrisched::ExpressionPtr chooseExpression = std::make_shared("task2", partitions, 1, 10, - 20); + 20, 1); // Try to meet both of the Expressions. tetrisched::ExpressionPtr minExpression = @@ -393,7 +393,7 @@ TEST(Expression, TestMalleableChooseExpressionConstruction) { // Construct the MalleableChooseExpression. tetrisched::ExpressionPtr malleableChooseExpression = std::make_shared( - "task1", partitions, 15, 5, 10, 1); + "task1", partitions, 15, 5, 10, 1, 1); // Construct an ObjectiveExpression. tetrisched::ExpressionPtr objectiveExpression = @@ -431,7 +431,7 @@ TEST(Expression, TestMalleableChooseExpressionConstructsVariableRectangles) { // usage. tetrisched::ExpressionPtr malleableChooseExpression = std::make_shared( - "task2", partitions, 10, 4, 10, 1); + "task2", partitions, 10, 4, 10, 1, 1); // Construct an ObjectiveExpression. tetrisched::ExpressionPtr objectiveExpression = diff --git a/schedulers/tetrisched_scheduler.py b/schedulers/tetrisched_scheduler.py index f0c5f844..3763cedd 100644 --- a/schedulers/tetrisched_scheduler.py +++ b/schedulers/tetrisched_scheduler.py @@ -1,7 +1,8 @@ import time from typing import List, Mapping, Optional, Set -import absl # noqa: F401 +import absl # noqa: F401 +import numpy as np import tetrisched_py as tetrisched from schedulers import BaseScheduler @@ -338,6 +339,16 @@ def construct_task_strl( current_time, task.deadline - execution_strategy.runtime ) + time_range = [time_discretization.time for time_discretization in time_discretizations] + # The placement reward skews the reward towards placing the task earlier. + # We interpolate the time range to a range between 2 and 1 and use that to + # skew the reward towards earlier placement. + placement_rewards = dict( + zip( + time_range, + np.interp(time_range, (min(time_range), max(time_range)), (2, 1)), + ) + ) task_choose_expressions = [] for placement_time in time_discretizations: if placement_time < current_time and task.state != TaskState.RUNNING: @@ -355,6 +366,7 @@ def construct_task_strl( num_slots_required, placement_time.time, execution_strategy.runtime.to(EventTime.Unit.US).time, + placement_rewards[placement_time.time], ) )