1classdef ParetoSweep < handle
2 % ParetoSweep Epsilon-constraint sweep
for bi-objective tradeoff analysis.
3 % Solves
the problem once per epsilon, each time adding
4 % constraintFactory(epsilon), and filters to
the non-dominated cost
5 % frontier. Mirrors native-Python ParetoSweep.
7 % constraintFactory
is a function handle mapping an epsilon to an
8 % opt.Constraint. solver
is 'de' (
default) or
'bisection'.
19 function obj = ParetoSweep(problem, constraintFactory, epsilons, solver)
20 obj.problem = problem;
21 obj.constraintFactory = constraintFactory;
22 obj.epsilons = epsilons;
23 if nargin >= 4 && ~isempty(solver), obj.solver = solver; end
26 function p = getPoints(obj), p = obj.points; end
28 function clone = cloneProblem(obj, epsilon)
29 clone = opt.OptimizationProblem(obj.problem.getModel());
30 vars = obj.problem.getVariables();
31 for i = 1:numel(vars), clone.addVariable(vars{i}); end
32 clone.setObjective(obj.problem.getObjective());
33 cons = obj.problem.getConstraints();
34 for i = 1:numel(cons), clone.addConstraint(cons{i}); end
35 clone.setFixedVariables(obj.problem.getFixedVariables());
36 scen = obj.problem.getScenarios();
37 for i = 1:numel(scen), clone.addScenario(scen{i}{1}, scen{i}{2}); end
38 clone.addConstraint(obj.constraintFactory(epsilon));
41 function pts = solve(obj, options)
42 if nargin < 2, options = opt.LineOptSolverOptions(); end
44 for i = 1:numel(obj.epsilons)
45 epsilon = obj.epsilons(i);
46 clone = obj.cloneProblem(epsilon);
47 if strcmp(obj.solver, 'bisection')
48 result = opt.BisectionSolver(clone).solve();
50 result = clone.solve(options);
52 obj.points{end+1} = opt.ParetoPoint(epsilon, result.objectiveValue, ...
53 result.feasible, result); %#ok<AGROW>
58 function frontier = getFrontier(obj)
60 for i = 1:numel(obj.points)
61 if obj.points{i}.feasible, feasible{end+1} = obj.points{i}; end %#ok<AGROW>
64 for i = 1:numel(feasible)
67 for j = 1:numel(feasible)
69 if q.objectiveValue <= p.objectiveValue && q.epsilon <= p.epsilon && ...
70 (q.objectiveValue < p.objectiveValue || q.epsilon < p.epsilon)
71 dominated =
true;
break;
74 if ~dominated, frontier{end+1} = p; end %#ok<AGROW>
78 eps = cellfun(@(x) x.epsilon, frontier);
80 frontier = frontier(ord);