LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
QBD.m
1classdef QBD < handle
2 properties (Access = private)
3 A_plus = {};
4 A_0 = {};
5 A_minus = {};
6 end
7
8 methods
9 function values = all_A_plus(obj)
10 values = obj.A_plus;
11 end
12
13 function values = all_A_0(obj)
14 values = obj.A_0;
15 end
16
17 function values = all_A_minus(obj)
18 values = obj.A_minus;
19 end
20
21 function matrix = get_A_minus(obj, level)
22 if level == 0
23 libqbd.raise_error('Matrix A_minus for zero level is undefined.');
24 end
25 if isempty(obj.A_minus)
26 libqbd.raise_error('No levels specified.');
27 end
28
29 idx = min(level, numel(obj.A_minus));
30 matrix = obj.A_minus{idx};
31 end
32
33 function matrix = get_A_0(obj, level)
34 if isempty(obj.A_0)
35 libqbd.raise_error('No levels specified.');
36 end
37
38 idx = min(level + 1, numel(obj.A_0));
39 matrix = obj.A_0{idx};
40 end
41
42 function matrix = get_A_plus(obj, level)
43 if isempty(obj.A_plus)
44 libqbd.raise_error('No levels specified.');
45 end
46
47 idx = min(level + 1, numel(obj.A_plus));
48 matrix = obj.A_plus{idx};
49 end
50
51 function add_zero_level(obj, varargin)
52 if ~(isempty(obj.A_0) && isempty(obj.A_plus))
53 libqbd.raise_error('Level zero already exists.');
54 end
55
56 if nargin == 2
57 A_plus = varargin{1};
58 obj.A_plus{1} = A_plus;
59 obj.A_0{1} = diag(-sum(A_plus, 2));
60 return;
61 end
62
63 A_0 = varargin{1};
64 A_plus = varargin{2};
65 if size(A_0, 1) ~= size(A_plus, 1)
66 libqbd.raise_error('Different number of rows in matrices of the same level.');
67 end
68 if size(A_0, 1) ~= size(A_0, 2)
69 libqbd.raise_error('Matrix A(0) is not square.');
70 end
71
72 obj.A_0{1} = A_0;
73 obj.A_plus{1} = A_plus;
74 end
75
76 function add_level(obj, varargin)
77 obj.check_filled_levels();
78
79 if nargin == 3
80 A_minus = varargin{1};
81 A_plus = varargin{2};
82 if size(A_minus, 1) ~= size(A_plus, 1)
83 libqbd.raise_error('Different number of rows in matrices of the same level.');
84 end
85 if size(A_minus, 2) ~= size(obj.A_0{end}, 2)
86 libqbd.raise_error('The number of columns of the matrix A(-) is not equal to the number of columns of the matrix A(0) of the previous level.');
87 end
88
89 obj.A_minus{end + 1} = A_minus;
90 obj.A_0{end + 1} = diag(-(sum(A_minus, 2) + sum(A_plus, 2)));
91 obj.A_plus{end + 1} = A_plus;
92 return;
93 end
94
95 A_minus = varargin{1};
96 A_0 = varargin{2};
97 A_plus = varargin{3};
98 if size(A_minus, 1) ~= size(A_0, 1) || size(A_minus, 1) ~= size(A_plus, 1)
99 libqbd.raise_error('Different number of rows in matrices of the same level.');
100 end
101 if size(A_minus, 2) ~= size(obj.A_0{end}, 2)
102 libqbd.raise_error('The number of columns of the matrix A(-) is not equal to the number of columns of the matrix A(0) of the previous level.');
103 end
104 if size(A_0, 2) ~= size(obj.A_plus{end}, 2)
105 libqbd.raise_error('The number of columns of the matrix A(0) is not equal to the number of columns of the matrix A(+) of the previous level.');
106 end
107 if size(A_0, 1) ~= size(A_0, 2)
108 libqbd.raise_error('Matrix A(0) is not square.');
109 end
110
111 obj.A_minus{end + 1} = A_minus;
112 obj.A_0{end + 1} = A_0;
113 obj.A_plus{end + 1} = A_plus;
114 end
115
116 function add_final_level(obj, varargin)
117 obj.check_filled_levels();
118
119 if nargin == 2
120 A_minus = varargin{1};
121 if size(A_minus, 1) ~= size(obj.A_plus{end}, 1)
122 libqbd.raise_error('Different number of rows in matrices of the same level.');
123 end
124 if size(A_minus, 2) ~= size(obj.A_0{end}, 2)
125 libqbd.raise_error('The number of columns of the matrix A(-) is not equal to the number of columns of the matrix A(0) of the previous level.');
126 end
127 if size(A_minus, 1) ~= size(A_minus, 2)
128 libqbd.raise_error('Matrix A(-) is not square.');
129 end
130 if size(obj.A_plus{end}, 1) ~= size(obj.A_plus{end}, 2)
131 libqbd.raise_error('Matrix A(+) is not square.');
132 end
133
134 obj.A_minus{end + 1} = A_minus;
135 obj.A_0{end + 1} = diag(-(sum(A_minus, 2) + sum(obj.A_plus{end}, 2)));
136 obj.A_plus{end + 1} = obj.A_plus{end};
137 return;
138 end
139
140 A_minus = varargin{1};
141 A_0 = varargin{2};
142 if size(A_minus, 1) ~= size(A_0, 1) || size(A_minus, 1) ~= size(obj.A_plus{end}, 1)
143 libqbd.raise_error('Different number of rows in matrices of the same level.');
144 end
145 if size(A_minus, 2) ~= size(obj.A_0{end}, 2)
146 libqbd.raise_error('The number of columns of the matrix A(-) is not equal to the number of columns of the matrix A(0) of the previous level.');
147 end
148 if size(A_0, 2) ~= size(obj.A_plus{end}, 2)
149 libqbd.raise_error('The number of columns of the matrix A(0) is not equal to the number of columns of the matrix A(+) of the previous level.');
150 end
151 if size(A_minus, 1) ~= size(A_minus, 2)
152 libqbd.raise_error('Matrix A(-) is not square.');
153 end
154 if size(A_0, 1) ~= size(A_0, 2)
155 libqbd.raise_error('Matrix A(0) is not square.');
156 end
157 if size(obj.A_plus{end}, 1) ~= size(obj.A_plus{end}, 2)
158 libqbd.raise_error('Matrix A(+) is not square.');
159 end
160
161 obj.A_minus{end + 1} = A_minus;
162 obj.A_0{end + 1} = A_0;
163 obj.A_plus{end + 1} = obj.A_plus{end};
164 end
165
166 function fix_diagonal(obj)
167 if ~(isempty(obj.A_0) || isempty(obj.A_plus))
168 obj.A_0{1} = obj.adjust_diagonal(obj.A_0{1}, sum(obj.A_plus{1}, 2) + sum(obj.A_0{1}, 2));
169 end
170
171 n = min([numel(obj.A_0), numel(obj.A_plus), numel(obj.A_minus) + 1]);
172 for k = 2:n
173 delta = sum(obj.A_minus{k - 1}, 2) + sum(obj.A_plus{k}, 2) + sum(obj.A_0{k}, 2);
174 obj.A_0{k} = obj.adjust_diagonal(obj.A_0{k}, delta);
175 end
176 end
177
178 function value = get_min_element(obj)
179 value = 0.0;
180 for k = 1:numel(obj.A_0)
181 diag_values = diag(obj.A_0{k});
182 value = min(value, min(diag_values));
183 end
184 end
185
186 function res = mull_by_row_vector(obj, vec, cons)
187 if nargin < 3
188 cons = 1.0;
189 end
190
191 n = numel(vec);
192 if n == 0
193 libqbd.raise_error('An empty vector was passed.');
194 end
195
196 vec = cellfun(@libqbd.as_row_vector, vec, 'UniformOutput', false);
197 res = {};
198
199 if n >= 3
200 res{1} = (vec{1} * obj.get_A_0(0) + vec{2} * obj.get_A_minus(1)) * cons;
201 for p = 3:n
202 res{p - 1} = (vec{p - 2} * obj.get_A_plus(p - 3) + vec{p - 1} * obj.get_A_0(p - 2) + vec{p} * obj.get_A_minus(p - 1)) * cons;
203 end
204 res{n} = (vec{n - 1} * obj.get_A_plus(n - 2) + vec{n} * obj.get_A_0(n - 1)) * cons;
205 tmp = (vec{n} * obj.get_A_plus(n - 1)) * cons;
206 if norm(tmp, 1) > 0.0
207 res{n + 1} = tmp;
208 end
209 elseif n == 2
210 res{1} = (vec{1} * obj.get_A_0(0) + vec{2} * obj.get_A_minus(1)) * cons;
211 res{2} = (vec{1} * obj.get_A_plus(0) + vec{2} * obj.get_A_0(1)) * cons;
212 res{3} = (vec{2} * obj.get_A_plus(1)) * cons;
213 else
214 res{1} = (vec{1} * obj.get_A_0(0)) * cons;
215 res{2} = (vec{1} * obj.get_A_plus(0)) * cons;
216 end
217 end
218 end
219
220 methods (Access = private)
221 function check_filled_levels(obj)
222 if numel(obj.A_0) ~= numel(obj.A_plus) || numel(obj.A_plus) ~= (numel(obj.A_minus) + 1)
223 libqbd.raise_error('Unfilled levels found.');
224 end
225 end
226
227 function matrix = adjust_diagonal(~, matrix, delta)
228 idx = 1:(size(matrix, 1) + 1):numel(matrix);
229 matrix(idx) = matrix(idx) - reshape(delta, 1, []);
230 end
231 end
232end