LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
BisectionSolver.m
1classdef BisectionSolver < handle
2 % BisectionSolver Exact O(log n) solver for a single integer decision
3 % variable with monotone feasibility. direction='min_feasible' finds the
4 % smallest feasible value (server sizing); 'max_feasible' the largest
5 % (population sizing). Mirrors native-Python
6 % line_solver.opt.sizing.BisectionSolver.
7
8 properties
9 problem
10 direction = 'min_feasible';
11 variable
12 lo
13 hi
14 fixedValueDict
15 evaluators
16 baseResultAt = [];
17 violationsAt
18 probeCache
19 end
20
21 methods
22 function obj = BisectionSolver(problem, direction)
23 obj.problem = problem;
24 if nargin >= 2 && ~isempty(direction), obj.direction = direction; end
25 vars = problem.getVariables();
26 if numel(vars) ~= 1 || vars{1}.getDimension() ~= 1
27 line_error(mfilename, 'BisectionSolver requires exactly one dimension-1 decision variable');
28 end
29 obj.variable = vars{1};
30 loV = obj.variable.decode(0.0);
31 hiV = obj.variable.decode(1.0);
32 if mod(loV,1) ~= 0 || mod(hiV,1) ~= 0
33 line_error(mfilename, 'BisectionSolver requires an integer-valued variable');
34 end
35 obj.lo = round(loV); obj.hi = round(hiV);
36
37 obj.fixedValueDict = containers.Map('KeyType','char','ValueType','any');
38 fixed = problem.getFixedVariables();
39 for k = 1:numel(fixed), obj.fixedValueDict(fixed{k}{1}.getName()) = fixed{k}{2}; end
40 obj.evaluators = {opt.LineEvaluator(problem.getModel(), vars, fixed)};
41 scen = problem.getScenarios();
42 for i = 1:numel(scen)
43 obj.evaluators{end+1} = opt.LineEvaluator(scen{i}{1}, vars, fixed); %#ok<AGROW>
44 end
45 obj.violationsAt = containers.Map('KeyType','char','ValueType','double');
46 obj.probeCache = containers.Map('KeyType','double','ValueType','any');
47 end
48
49 function cons = allConstraints(obj)
50 objective = obj.problem.getObjective();
51 cons = {};
52 if ~isempty(objective), cons = objective.getConstraints(); end
53 cons = [cons, obj.problem.getConstraints()];
54 end
55
56 function feasible = probe(obj, value)
57 if isKey(obj.probeCache, value)
58 c = obj.probeCache(value);
59 obj.baseResultAt = c{2}; obj.violationsAt = c{3};
60 feasible = c{1}; return;
61 end
62 values = containers.Map('KeyType','char','ValueType','any');
63 values(obj.variable.getName()) = value;
64 allValues = containers.Map('KeyType','char','ValueType','any');
65 fk = keys(obj.fixedValueDict);
66 for i = 1:numel(fk), allValues(fk{i}) = obj.fixedValueDict(fk{i}); end
67 allValues(obj.variable.getName()) = value;
68 cons = obj.allConstraints();
69
70 feasible = true;
71 violations = containers.Map('KeyType','char','ValueType','double');
72 baseResult = [];
73 for e = 1:numel(obj.evaluators)
74 res = obj.evaluators{e}.evaluateValues(values);
75 if isempty(baseResult), baseResult = res; end
76 if ~res.feasible, feasible = false; continue; end
77 for c = 1:numel(cons)
78 v = cons{c}.evaluate(res, allValues);
79 if v > 0
80 feasible = false;
81 nm = cons{c}.getName();
82 prev = 0.0; if isKey(violations, nm), prev = violations(nm); end
83 violations(nm) = max(v, prev);
84 end
85 end
86 end
87 obj.baseResultAt = baseResult;
88 obj.violationsAt = violations;
89 obj.probeCache(value) = {feasible, baseResult, violations};
90 end
91
92 function result = solve(obj)
93 t0 = tic;
94 loV = obj.lo; hiV = obj.hi; iterations = 0;
95 if strcmp(obj.direction, 'min_feasible')
96 while loV < hiV
97 mid = floor((loV + hiV) / 2);
98 feasible = obj.probe(mid); iterations = iterations + 1;
99 if feasible, hiV = mid; else, loV = mid + 1; end
100 end
101 elseif strcmp(obj.direction, 'max_feasible')
102 while loV < hiV
103 mid = floor((loV + hiV + 1) / 2);
104 feasible = obj.probe(mid); iterations = iterations + 1;
105 if feasible, loV = mid; else, hiV = mid - 1; end
106 end
107 else
108 line_error(mfilename, ['Unknown direction: ' obj.direction]);
109 end
110
111 chosen = loV;
112 feasible = obj.probe(chosen);
113
114 result = opt.OptimizationResult();
115 result.variableValues(obj.variable.getName()) = chosen;
116 result.feasible = feasible;
117 vk = keys(obj.violationsAt);
118 for i = 1:numel(vk), result.constraintViolations(vk{i}) = obj.violationsAt(vk{i}); end
119 result.iterations = iterations;
120 evals = 0;
121 for e = 1:numel(obj.evaluators), evals = evals + obj.evaluators{e}.getEvaluationCount(); end
122 result.modelEvaluations = evals;
123 result.terminatedBy = 'bisection';
124
125 objective = obj.problem.getObjective();
126 if ~isempty(objective) && ~isempty(obj.baseResultAt)
127 allValues = containers.Map('KeyType','char','ValueType','any');
128 fk = keys(obj.fixedValueDict);
129 for i = 1:numel(fk), allValues(fk{i}) = obj.fixedValueDict(fk{i}); end
130 allValues(obj.variable.getName()) = chosen;
131 result.objectiveValue = objective.evaluate(obj.baseResultAt, allValues);
132 end
133 result.solveTime = toc(t0);
134 end
135 end
136end
Definition Station.m:245