5#ifndef LINE_OPT_LAYERED_VARIABLES_H
6#define LINE_OPT_LAYERED_VARIABLES_H
32namespace layered_detail {
34inline std::size_t processor(
const lqn::LqnModel<double>& model,
const std::string& name) {
35 for (std::size_t i = 0; i < model.procs.size(); ++i)
36 if (model.procs[i].name == name)
return i;
37 return model.procs.size();
39inline std::size_t task(
const lqn::LqnModel<double>& model,
const std::string& name) {
40 for (std::size_t i = 0; i < model.tasks.size(); ++i)
41 if (model.tasks[i].name == name)
return i;
42 return model.tasks.size();
44inline std::size_t activity(
const lqn::LqnModel<double>& model,
const std::string& name) {
45 for (std::size_t i = 0; i < model.acts.size(); ++i)
46 if (model.acts[i].name == name)
return i;
47 return model.acts.size();
49inline std::string task_processor(
const lqn::LqnModel<double>& model,
50 const std::string& task_name) {
51 const std::size_t index = task(model, task_name);
52 if (index >= model.tasks.size() || model.tasks[index].proc_slot >= model.procs.size())
54 return model.procs[model.tasks[index].proc_slot].name;
56inline std::string activity_task(
const lqn::LqnModel<double>& model,
57 const std::string& activity_name) {
58 const std::size_t index = activity(model, activity_name);
59 if (index >= model.acts.size() || model.acts[index].task_slot >= model.tasks.size())
61 return model.tasks[model.acts[index].task_slot].name;
63inline std::string activity_processor(
const lqn::LqnModel<double>& model,
64 const std::string& activity_name) {
65 return task_processor(model, activity_task(model, activity_name));
67inline Value integer_decode(
const std::vector<double>& x,
int low,
int high) {
68 return {
static_cast<double>(std::clamp<int>(
69 static_cast<int>(std::llround(low + x.at(0) * (high - low))), low, high))};
71inline Value continuous_decode(
const std::vector<double>& x,
double low,
double high) {
72 return {low + x.at(0) * (high - low)};
81 processor_(std::move(processor)), low_(low), high_(high) {}
83 return layered_detail::integer_decode(x, low_, high_);
86 const std::size_t i = layered_detail::processor(model, processor_);
89 std::string
type()
const override {
return "processor_multiplicity"; }
94 const std::size_t i = layered_detail::processor(model, processor_);
95 if (i >= model.
procs.size() || !std::isfinite(model.
procs[i].mult))
return std::nullopt;
99 std::string processor_;
107 task_(std::move(task)), low_(low), high_(high) {}
109 return layered_detail::integer_decode(x, low_, high_);
112 const std::size_t i = layered_detail::task(model, task_);
115 std::string
type()
const override {
return "task_multiplicity"; }
117 std::vector<std::string> out{task_};
118 const std::string processor = layered_detail::task_processor(model, task_);
119 if (!processor.empty()) out.push_back(processor);
123 const std::size_t i = layered_detail::task(model, task_);
124 if (i >= model.
tasks.size() || !std::isfinite(model.
tasks[i].mult))
return std::nullopt;
125 return Value{std::round(model.
tasks[i].mult)};
136 task_(std::move(task)), low_(low), high_(high) {}
138 return layered_detail::integer_decode(x, low_, high_);
141 const std::size_t i = layered_detail::task(model, task_);
144 std::string
type()
const override {
return "task_replication"; }
146 std::vector<std::string> out{task_};
147 const std::string processor = layered_detail::task_processor(model, task_);
148 if (!processor.empty()) out.push_back(processor);
152 const std::size_t i = layered_detail::task(model, task_);
153 if (i >= model.
tasks.size() || !std::isfinite(model.
tasks[i].repl))
return std::nullopt;
154 return Value{std::round(model.
tasks[i].repl)};
165 activity_(std::move(activity)), low_(low), high_(high) {}
167 return layered_detail::continuous_decode(x, low_, high_);
170 const std::size_t i = layered_detail::activity(model, activity_);
171 if (i < model.
acts.size())
174 std::string
type()
const override {
return "host_demand"; }
176 const std::string processor = layered_detail::activity_processor(model, activity_);
177 return processor.empty() ? std::vector<std::string>()
178 : std::vector<std::string>{processor};
181 const std::size_t i = layered_detail::activity(model, activity_);
182 if (i >= model.
acts.size() || model.
acts[i].hostdem.disabled)
return std::nullopt;
183 return Value{model.
acts[i].hostdem.mean};
187 const std::string processor = layered_detail::activity_processor(model, activity_);
188 const std::string task = layered_detail::activity_task(model, activity_);
189 return processor.empty() || task.empty() ? std::string()
190 : processor +
"||" + task;
194 const std::string processor = layered_detail::activity_processor(model, activity_);
195 return {{
"Util", processor}, {
"Tput",
metric_key(activity_, activity_)},
201 return demand <= 0.0 ? 0.0 : -1.0 / (demand * demand);
205 std::string activity_;
213 task_(std::move(task)), low_(low), high_(high) {}
215 return layered_detail::continuous_decode(x, low_, high_);
218 const std::size_t i = layered_detail::task(model, task_);
219 if (i < model.
tasks.size())
222 std::string
type()
const override {
return "think_time"; }
224 std::vector<std::string> out{task_};
225 const std::string processor = layered_detail::task_processor(model, task_);
226 if (!processor.empty()) out.push_back(processor);
230 const std::size_t i = layered_detail::task(model, task_);
231 if (i >= model.
tasks.size() || model.
tasks[i].thinktime.disabled)
return std::nullopt;
243 activity_(std::move(activity)), low_(low), high_(high) {}
245 return layered_detail::continuous_decode(x, low_, high_);
248 const std::size_t i = layered_detail::activity(model, activity_);
249 if (i < model.
acts.size())
252 std::string
type()
const override {
return "think_time"; }
254 std::vector<std::string> out;
255 const std::string task = layered_detail::activity_task(model, activity_);
256 const std::string processor = layered_detail::activity_processor(model, activity_);
257 if (!task.empty()) out.push_back(task);
258 if (!processor.empty()) out.push_back(processor);
262 const std::size_t i = layered_detail::activity(model, activity_);
263 if (i >= model.
acts.size() || model.
acts[i].thinktime.disabled)
return std::nullopt;
264 return Value{model.
acts[i].thinktime.mean};
267 std::string activity_;
std::string type() const override
std::optional< Value > current_value(const lqn::LqnModel< double > &model) const override
std::vector< std::string > layers(const lqn::LqnModel< double > &model) const override
ActivityThinkTime(std::string activity, double low, double high, std::string name="")
Value decode(const std::vector< double > &x) const override
void apply(lqn::LqnModel< double > &model, const Value &value) const override
DecisionVariable(std::string n, std::size_t d=1)
const std::string & name() const
void apply(lqn::LqnModel< double > &model, const Value &value) const override
double rate_jacobian(const Value &value) const override
std::optional< Value > current_value(const lqn::LqnModel< double > &model) const override
std::vector< std::string > layers(const lqn::LqnModel< double > &model) const override
double decode_jacobian(double) const override
std::map< std::string, std::string > sensitivity_metric_targets(const lqn::LqnModel< double > &model) const override
HostDemand(std::string activity, double low, double high, std::string name="")
Value decode(const std::vector< double > &x) const override
std::string type() const override
bool supports_sensitivity() const override
std::string sensitivity_key(const lqn::LqnModel< double > &model) const override
std::string type() const override
ProcessorMultiplicity(std::string processor, int low, int high, std::string name="")
Value decode(const std::vector< double > &x) const override
void apply(lqn::LqnModel< double > &model, const Value &value) const override
std::vector< std::string > layers(const lqn::LqnModel< double > &) const override
std::optional< Value > current_value(const lqn::LqnModel< double > &model) const override
TaskMultiplicity(std::string task, int low, int high, std::string name="")
std::string type() const override
Value decode(const std::vector< double > &x) const override
std::vector< std::string > layers(const lqn::LqnModel< double > &model) const override
std::optional< Value > current_value(const lqn::LqnModel< double > &model) const override
void apply(lqn::LqnModel< double > &model, const Value &value) const override
std::string type() const override
TaskReplication(std::string task, int low, int high, std::string name="")
void apply(lqn::LqnModel< double > &model, const Value &value) const override
std::optional< Value > current_value(const lqn::LqnModel< double > &model) const override
Value decode(const std::vector< double > &x) const override
std::vector< std::string > layers(const lqn::LqnModel< double > &model) const override
Value decode(const std::vector< double > &x) const override
std::string type() const override
TaskThinkTime(std::string task, double low, double high, std::string name="")
std::optional< Value > current_value(const lqn::LqnModel< double > &model) const override
std::vector< std::string > layers(const lqn::LqnModel< double > &model) const override
void apply(lqn::LqnModel< double > &model, const Value &value) const override
double scalar_value(const Value &v)
std::string metric_key(const std::string &station, const std::string &jobclass)
std::vector< double > Value
static Distrib exp_mean(const T &m)
The intermediate model, and the second stage that flattens it.
std::vector< detail::RawTask< T > > tasks
std::vector< detail::RawActivity< T > > acts
std::vector< detail::RawProc > procs
The decision variables of a flat queueing network.