1classdef OptimizationProblem < handle
2 % OptimizationProblem Declarative specification of a queueing-network
3 % optimization problem. Mirrors native-Python
4 % line_solver.opt.problem.OptimizationProblem.
8 variables = {}; % cell of opt.DecisionVariable
10 constraints = {}; % cell of opt.Constraint
11 fixedVariables = {}; % cell of {var, value}
12 scenarios = {}; % cell of {model, weight}
13 isLayeredModel =
false;
17 % Decision-variable types operating on a LayeredNetwork vs a flat one.
18 LQN_VAR_TYPES = {
'host_demand',
'think_time',
'task_multiplicity', ...
19 'task_replication',
'processor_multiplicity'};
20 FLAT_VAR_TYPES = {
'server_allocation',
'station_replicas', ...
21 'service_rate',
'job_population',
'class_priority',
'routing', ...
26 function obj = OptimizationProblem(model)
28 obj.isLayeredModel = opt.Layered.isLayered(model);
31 function tf = isLayered(obj), tf = obj.isLayeredModel; end
32 function m = getModel(obj), m = obj.model; end
33 function v = getVariables(obj), v = obj.variables; end
34 function o = getObjective(obj), o = obj.objective; end
35 function c = getConstraints(obj), c = obj.constraints; end
37 function obj = addVariable(obj, variable)
38 obj.variables{end+1} = variable;
40 function obj = setObjective(obj, objective)
41 obj.objective = objective;
43 function obj = addConstraint(obj, constraint)
44 obj.constraints{end+1} = constraint;
46 function obj = setFixedVariables(obj, pairs)
47 obj.fixedVariables = pairs;
49 function p = getFixedVariables(obj), p = obj.fixedVariables; end
50 function obj = addScenario(obj, scenarioModel, weight)
51 if nargin < 3, weight = 1.0; end
52 obj.scenarios{end+1} = {scenarioModel, weight};
54 function s = getScenarios(obj), s = obj.scenarios; end
56 function errors = validate(obj)
58 if isempty(obj.model), errors{end+1} =
'Model is not set'; end
59 if isempty(obj.variables), errors{end+1} =
'No decision variables defined'; end
60 if isempty(obj.objective), errors{end+1} =
'Objective function is not set'; end
62 % Model/variable-kind consistency: LQN models take LQN variables and
63 % flat models take flat variables; mixing them silently produces
64 % no-ops (a variable whose element
is never found in the copy).
65 for i = 1:numel(obj.variables)
66 vt = obj.variables{i}.getVariableType();
67 nm = obj.variables{i}.getName();
68 if obj.isLayeredModel && any(strcmp(vt, obj.FLAT_VAR_TYPES))
69 errors{end+1} = sprintf([
'Variable ''%s'' (%s) is a ' ...
70 'flat-network variable but the model is a ' ...
71 'LayeredNetwork'], nm, vt); %#ok<AGROW>
72 elseif ~obj.isLayeredModel && any(strcmp(vt, obj.LQN_VAR_TYPES))
73 errors{end+1} = sprintf([
'Variable ''%s'' (%s) is a ' ...
74 'LayeredNetwork variable but the model is a flat ' ...
75 'Network'], nm, vt); %#ok<AGROW>
80 function tf = isValid(obj)
81 tf = isempty(obj.validate());
84 function result = solve(obj, options)
85 errors = obj.validate();
87 line_error(mfilename, [
'Invalid problem: ' strjoin(errors,
', ')]);
89 if nargin < 2 || isempty(options)
90 options = opt.LineOptSolverOptions();
92 solver = opt.LineOptSolver(obj, options);
93 result = solver.solve();
96 function workflow = decompose(obj)
97 workflow = opt.DecompositionWorkflow(obj);