LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
TaylorSeriesAdaptive.m
1classdef TaylorSeriesAdaptive < handle
2 properties (Access = private)
3 is_binded = false
4 max_saved_data = 0
5 max_degree = 0
6 proc
7 dist_in_ref_points = {}
8 norms_in_ref_points = {}
9 derivs_in_ref_points = {}
10 ref_points = []
11 clients_in_ref_points = []
12 min_elem = 0.0
13 error = 0.0
14 end
15
16 methods
17 function obj = TaylorSeriesAdaptive(proc, pi0, error_value, max_time, approx_type, strategy)
18 if nargin > 0
19 if nargin < 5
20 approx_type = libqbd.APPROX_TAYLOR_UNLIM();
21 end
22 if nargin < 6
23 strategy = libqbd.STRATEGY_FAST();
24 end
25 obj.bind(proc, pi0, error_value, max_time, approx_type, strategy);
26 end
27 end
28
29 function bind(obj, proc, pi0, error_value, max_time, approx_type, strategy)
30 if nargin < 6
31 approx_type = libqbd.APPROX_TAYLOR_UNLIM();
32 end
33 if nargin < 7
34 strategy = libqbd.STRATEGY_FAST();
35 end
36 if obj.is_binded
37 libqbd.raise_error('Already binded.');
38 end
39
40 obj.min_elem = -proc.get_min_element();
41 obj.proc = proc;
42 obj.dist_in_ref_points = {pi0};
43 obj.norms_in_ref_points = {{}};
44 obj.derivs_in_ref_points = {{}};
45 obj.ref_points = 0.0;
46 obj.error = error_value;
47 obj.max_degree = libqbd.parse_approx_type(approx_type);
48 obj.max_saved_data = min(obj.max_degree, double(strategy));
49 while obj.ref_points(end) < max_time
50 obj.next_point(libqbd.get_max_factor());
51 end
52 obj.is_binded = true;
53 end
54
55 function values = get_reference_times(obj)
56 obj.check();
57 values = obj.ref_points;
58 end
59
60 function values = get_reference_dists(obj)
61 obj.check();
62 values = obj.dist_in_ref_points;
63 end
64
65 function [dist, errors] = get_dist(obj, times)
66 obj.check();
67 errors = [];
68 if isempty(times)
69 dist = {};
70 return;
71 end
72
73 while obj.ref_points(end) < times(end)
74 obj.next_point(libqbd.get_max_factor());
75 end
76
77 num = obj.find_max_le_t(times(1), 1);
78 norm_times = [];
79 dist = {};
80 errors = [];
81 for t = times
82 reg = (t - obj.ref_points(num)) * obj.min_elem;
83 if reg > 1.0
84 [dist, errors] = obj.calc_intermed_points(dist, errors, norm_times, num);
85 norm_times = [];
86 num = obj.find_max_le_t(t, num);
87 reg = (t - obj.ref_points(num)) * obj.min_elem;
88 end
89 norm_times(end + 1) = reg; %#ok<AGROW>
90 end
91
92 if ~isempty(norm_times)
93 [dist, errors] = obj.calc_intermed_points(dist, errors, norm_times, num);
94 end
95 end
96
97 function values = get_reference_mean_clients(obj)
98 obj.check();
99 if numel(obj.clients_in_ref_points) < numel(obj.ref_points)
100 for k = (numel(obj.clients_in_ref_points) + 1):numel(obj.ref_points)
101 obj.clients_in_ref_points(end + 1) = libqbd.function_of_dist(obj.dist_in_ref_points{k}, @client_weights); %#ok<AGROW>
102 end
103 end
104 values = obj.clients_in_ref_points;
105
106 function weights = client_weights(level, length)
107 weights = ones(1, length) * level;
108 end
109 end
110 end
111
112 methods (Access = private)
113 function check(obj)
114 if ~obj.is_binded
115 libqbd.raise_error('Not binded to the process.');
116 end
117 if isempty(obj.proc.all_A_0())
118 libqbd.raise_error('Infinitesimal generator matrix is empty.');
119 end
120 end
121
122 function next_point(obj, n)
123 deriv = obj.dist_in_ref_points{end};
124 res = deriv;
125 norms = {};
126 derivs = {};
127 k = 0;
128 two_delta_inv = 0.5;
129 two_delta_in_n = two_delta_inv;
130 min_elem_inv = 1.0 / obj.min_elem;
131 er = inf;
132 while er > obj.error && k < n
133 deriv = obj.proc.mull_by_row_vector(deriv, min_elem_inv);
134 res = libqbd.vec_fma(res, deriv, libqbd.get_one_div_by_factor(k));
135 norm_value = libqbd.l1norm_cell(deriv);
136 er = norm_value * gammainc(2.0, k + 2.0, 'lower') * exp(2.0) * two_delta_in_n;
137 if numel(norms) < obj.max_saved_data
138 norms{end + 1} = norm_value; %#ok<AGROW>
139 derivs{end + 1} = deriv; %#ok<AGROW>
140 end
141 two_delta_in_n = two_delta_in_n * two_delta_inv;
142 k = k + 1;
143 end
144 obj.dist_in_ref_points{end + 1} = res;
145 obj.ref_points(end + 1) = obj.ref_points(end) + 1.0 / obj.min_elem;
146 obj.norms_in_ref_points{end + 1} = norms;
147 obj.derivs_in_ref_points{end + 1} = derivs;
148 end
149
150 function [dist, errors] = calc_intermed_points(obj, dist, errors, deltas, num)
151 for d = deltas
152 if d <= eps
153 dist{end + 1} = obj.dist_in_ref_points{num}; %#ok<AGROW>
154 errors(end + 1) = 0.0; %#ok<AGROW>
155 continue;
156 end
157
158 res = obj.dist_in_ref_points{num};
159 deriv_comp = {};
160 k = 0;
161 delta_m = d;
162 delta_inv = 0.5;
163 delta_minus_n = delta_inv;
164 er = inf;
165 while k < obj.max_degree && er > obj.error
166 if k < numel(obj.norms_in_ref_points{num})
167 deriv = obj.derivs_in_ref_points{num}{k + 1};
168 norm_value = obj.norms_in_ref_points{num}{k + 1};
169 else
170 if isempty(deriv_comp)
171 if ~isempty(obj.derivs_in_ref_points{num})
172 deriv_comp = obj.derivs_in_ref_points{num}{end};
173 else
174 deriv_comp = obj.dist_in_ref_points{num};
175 end
176 end
177 deriv_comp = obj.proc.mull_by_row_vector(deriv_comp, 1.0 / obj.min_elem);
178 deriv = deriv_comp;
179 norm_value = libqbd.l1norm_cell(deriv_comp);
180 end
181
182 res = libqbd.vec_fma(res, deriv, delta_m * libqbd.get_one_div_by_factor(k));
183 delta_m = delta_m * d;
184 er = norm_value * gammainc(2.0 * d, k + 2.0, 'lower') * exp(2.0 * d) * delta_minus_n;
185 delta_minus_n = delta_minus_n * delta_inv;
186 k = k + 1;
187 end
188 dist{end + 1} = res; %#ok<AGROW>
189 errors(end + 1) = er; %#ok<AGROW>
190 end
191 end
192
193 function num = find_max_le_t(obj, t, num)
194 idx = find(obj.ref_points(num:end) <= t, 1, 'last');
195 if isempty(idx)
196 num = 1;
197 else
198 num = num + idx - 1;
199 end
200 end
201 end
202end