1 /* Siconos is a program dedicated to modeling, simulation and control
2 * of non smooth dynamical systems.
3 *
4 * Copyright 2021 INRIA.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include "SiconosMatrixSetBlock.hpp"
20 #include <boost/numeric/ublas/matrix_proxy.hpp>
21 #include <boost/numeric/ublas/triangular.hpp>
22 #include <boost/numeric/ublas/symmetric.hpp>
23 #include <boost/numeric/ublas/banded.hpp>
24 #include <boost/numeric/ublas/matrix_sparse.hpp>
25 #include "SiconosMatrix.hpp"
26 #include "SiconosException.hpp"
27
setBlock(SPC::SiconosMatrix input_matrix,SP::SiconosMatrix output_matrix,const Index & dim,const Index & start)28 void setBlock(SPC::SiconosMatrix input_matrix, SP::SiconosMatrix output_matrix, const Index& dim, const Index& start)
29 {
30 // To copy a subBlock of input_matrix into a subBlock of output_matrix.
31 // dim[0], dim[1]: number of rows and columns of the sub-block
32 // start[0], start[1]: position (row, column) of the first element of the subBlock in input_matrix
33 // start[2], start[3]: position (row, column) of the first element of the subBlock in output_matrix
34
35 if(input_matrix == output_matrix) // useless op => nothing to be done.
36 return;
37
38 Siconos::UBLAS_TYPE numIn = input_matrix->num();
39 Siconos::UBLAS_TYPE numOut = output_matrix->num();
40
41 if(numOut == Siconos::ZERO || numOut == Siconos::IDENTITY) // if output_matrix = 0 or Identity => read-only
42 THROW_EXCEPTION("output_matrix is read-only (zero or identity matrix?).");
43
44 // Check dimension
45 Index MDim(4); // dim. of matrices input_matrix and output_matrix.
46 MDim[0] = input_matrix->size(0);
47 MDim[1] = input_matrix->size(1);
48 MDim[2] = output_matrix->size(0);
49 MDim[3] = output_matrix->size(1);
50
51 for(unsigned int i = 0; i < 4 ; ++i)
52 if(start[i] >= MDim[i])
53 THROW_EXCEPTION("matrices, setBlock(input_matrix, ...): sub-block indices are out of range.");
54
55 // index position of the last element in subBlock ...
56 Index end(4);
57 end[0] = dim[0] + start[0];
58 end[1] = dim[1] + start[1];
59 end[2] = dim[0] + start[2];
60 end[3] = dim[1] + start[3];
61
62 for(unsigned int i = 0; i < 4 ; ++i)
63 if(end[i] > MDim[i])
64 THROW_EXCEPTION("sub-block last indices are out of range.");
65
66 // Elements from row/col start[i] to row/col (end[i]-1) will be copied.
67
68 // If both matrices input_matrix and output_matrix are block, exception.
69 if(numIn == Siconos::BLOCK && numOut == Siconos::BLOCK)
70 THROW_EXCEPTION("not yet implemented for input_matrix and output_matrix both BlockMatrix. Try to use setBlock on the sub-matrices?");
71
72 if(numOut == Siconos::BLOCK) // if output_matrix is a BlockMatrix.
73 {
74
75 // Steps:
76 // A - Find the blocks of output_matrix that "own" indices start[2] and end[2] ie
77 // the first and last sub-block to be set in a block-column
78 // --> numbers blockStart0 and blockEnd0
79 // B - Find the Block of output_matrix that "owns" index start[3] and end[3] ie
80 // the first sub-block to be set in a block-row
81 // --> numbers blockStart1 and blockEnd1
82 //
83 // => The blocks concerned in output_matrix, are those between (block) rows blockStart0 and blockEnd0
84 // and (block) columns blockStart1 and blockEnd1.
85 //
86 // C - Loop through the concerned blocks (name = currentBlock) of output_matrix and call setBlock(input_matrix, currentBlock, subSize, currentPos).
87 // subSize: dim. of the considered sub-block of currentBlock to be set
88 // currentPos: same as "start" vector but for currentBlock
89 //
90
91 // A - Block-Row position: we look for the block of output_matrix that include index start[2] and end[2].
92 //
93 unsigned int blockStart0 = 0;
94 SPC::Index tab = output_matrix->tabRow();
95 while(start[2] >= (*tab)[blockStart0] && blockStart0 < tab->size())
96 blockStart0 ++;
97 // Relative position in the block blockStart0 of the first element to be set.
98 unsigned int posOut0 = start[2];
99 if(blockStart0 != 0)
100 posOut0 -= (*tab)[blockStart0 - 1];
101
102 unsigned int blockEnd0 = blockStart0;
103 while(end[2] > (*tab)[blockEnd0] && blockEnd0 < tab->size())
104 blockEnd0 ++;
105
106 // Size of the last sub-block in the column of block
107 unsigned int lastBlockSize0 = end[2];
108 if(blockEnd0 != 0)
109 lastBlockSize0 -= (*tab)[blockEnd0 - 1];
110
111 // B - Block-Col position: we look for the block of output_matrix that include index start[3] and end[3].
112 unsigned int blockStart1 = 0;
113 tab = output_matrix->tabCol();
114 while(start[3] >= (*tab)[blockStart1] && blockStart1 < tab->size())
115 blockStart1 ++;
116 // Relative position in the block blockStart1 of the first element to be set.
117 unsigned int posOut1 = start[3];
118 if(blockStart1 != 0)
119 posOut1 -= (*tab)[blockStart1 - 1];
120
121 unsigned int blockEnd1 = blockStart1;
122 while(end[3] > (*tab)[blockEnd1] && blockEnd1 < tab->size())
123 blockEnd1 ++;
124
125 // Size of the last sub-block in the row of block
126 unsigned int lastBlockSize1 = end[3];
127 if(blockEnd1 != 0)
128 lastBlockSize1 -= (*tab)[blockEnd1 - 1];
129
130 //C - Next, 3 steps for each row:
131 // - set first sub-block in the row (number blockStart1)
132 // - set all other blocks in the row except the last one
133 // - set last block (number blockEnd1)
134 // Same process for other rows ...
135
136 // The current considered block
137 SP::SiconosMatrix currentBlock = output_matrix->block(blockStart0, blockStart1);
138
139 // dim of the subBlock of currentBlock to be set.
140 Index subSize(2);
141 // indices of the first element of input_matrix (resp. currentBlock) to be read (resp. set) (same as start for input_matrix and output_matrix).
142 Index currentPos(4);
143
144 // currentBlock position in output_matrix.
145 unsigned int numRow = blockStart0;
146 unsigned int numCol = blockStart1;
147
148 // Init currentPos
149 // row and col position for first element to be read in input_matrix,
150 currentPos[0] = start[0];
151 currentPos[1] = start[1];
152 // row and col position for first element in sub-block of Mout (namely currentBlock).
153 currentPos[2] = posOut0;
154 currentPos[3] = posOut1;
155
156 while(numRow != blockEnd0 + 1)
157 {
158
159 while(numCol != blockEnd1 + 1)
160 {
161 // Get the block of output_matrix from which a sub-block will be set ...
162 currentBlock = output_matrix->block(numRow, numCol);
163
164 // Set subSize[0], dim (rows) and subSize[1], dim (columns) of the sub-block.
165 // subSize[0] is only required for the first block in the row, after it remains constant.
166 subSize[1] = currentBlock->size(1);
167
168 // Warning: test "a" must be done before test "b"
169 if(numCol == blockEnd1) // if last column of blocks -> test "a"
170 subSize[1] = lastBlockSize1;
171
172 if(numCol == blockStart1) // -> test "b"
173 {
174 subSize[1] -= posOut1;
175 subSize[0] = currentBlock->size(0);
176 if(numRow == blockEnd0) // if last row of blocks
177 subSize[0] = lastBlockSize0;
178 if(numRow == blockStart0) // if first row of blocks
179 subSize[0] -= posOut0;
180 }
181
182 // Set sub-block
183 setBlock(input_matrix, currentBlock, subSize, currentPos);
184
185 // Update currentPos:
186 // col position for first element to be read in input_matrix,
187 currentPos[1] += subSize[1] ;
188 // col position for first element to be set in sub-block.
189 currentPos[3] = 0;
190 numCol++;
191 }
192
193 numCol = blockStart1;
194 numRow++;
195
196 // Update currentPos:
197 // row position for first element to be read in input_matrix,
198 currentPos[0] += subSize[0] ;
199 // col position for first element to be read in input_matrix,
200 currentPos[1] = start[1] ;
201 // row position for first element to be set in sub-block.
202 currentPos[2] = 0;
203 // col position for first element to be set in sub-block.
204 currentPos[3] = posOut1;
205
206 }
207
208 }
209 else if(numIn == Siconos::BLOCK) // If input_matrix is a BlockMatrix.
210 {
211
212 // Same process as for numOut == 0
213
214 unsigned int blockStart0 = 0;
215 SPC::Index tab = input_matrix->tabRow();
216 while(start[0] >= (*tab)[blockStart0] && blockStart0 < tab->size())
217 blockStart0 ++;
218 // Relative position in the block blockStart0 of the first element to be set.
219 unsigned int posOut0 = start[0];
220 if(blockStart0 != 0)
221 posOut0 -= (*tab)[blockStart0 - 1];
222
223 unsigned int blockEnd0 = blockStart0;
224 while(end[0] > (*tab)[blockEnd0] && blockEnd0 < tab->size())
225 blockEnd0 ++;
226
227 // Size of the last sub-block in the column of block
228 unsigned int lastBlockSize0 = end[0];
229 if(blockEnd0 != 0)
230 lastBlockSize0 -= (*tab)[blockEnd0 - 1];
231
232 // B - Block-Col position: we look for the block of output_matrix that include index start[3] and end[3].
233 unsigned int blockStart1 = 0;
234 tab = input_matrix->tabCol();
235 while(start[1] >= (*tab)[blockStart1] && blockStart1 < tab->size())
236 blockStart1 ++;
237 // Relative position in the block blockStart1 of the first element to be set.
238 unsigned int posOut1 = start[1];
239 if(blockStart1 != 0)
240 posOut1 -= (*tab)[blockStart1 - 1];
241
242 unsigned int blockEnd1 = blockStart1;
243 while(end[1] > (*tab)[blockEnd1] && blockEnd1 < tab->size())
244 blockEnd1 ++;
245
246 // Size of the last sub-block in the row of block
247 unsigned int lastBlockSize1 = end[1];
248 if(blockEnd1 != 0)
249 lastBlockSize1 -= (*tab)[blockEnd1 - 1];
250
251 //C - Next, 3 steps for each row:
252 // - set first sub-block in the row (number blockStart1)
253 // - set all other blocks in the row except the last one
254 // - set last block (number blockEnd1)
255 // Same process for other rows ...
256
257 // The current considered block
258 SPC::SiconosMatrix currentBlock = input_matrix->block(blockStart0, blockStart1);
259
260 // dim of the subBlock of currentBlock to be set.
261 Index subSize(2);
262 // indices of the first element of input_matrix (resp. currentBlock) to be read (resp. set) (same as start for input_matrix and output_matrix).
263 Index currentPos(4);
264
265 // currentBlock position in output_matrix.
266 unsigned int numRow = blockStart0;
267 unsigned int numCol = blockStart1;
268
269 // Init currentPos
270 // row and col position for first element to be read in input_matrix,
271 currentPos[0] = posOut0;
272 currentPos[1] = posOut1;
273 // row and col position for first element in sub-block of Mout (namely currentBlock).
274 currentPos[2] = start[2];
275 currentPos[3] = start[3];
276
277 while(numRow != blockEnd0 + 1)
278 {
279
280 while(numCol != blockEnd1 + 1)
281 {
282 // Get the block of output_matrix from which a sub-block will be set ...
283 currentBlock = input_matrix->block(numRow, numCol);
284
285 // Set subSize[0], dim (rows) and subSize[1], dim (columns) of the sub-block.
286 // subSize[0] is only required for the first block in the row, after it remains constant.
287 subSize[1] = currentBlock->size(1);
288 // Warning: test "a" must be done before test "b"
289 if(numCol == blockEnd1) // if last column of blocks -> test "a"
290 subSize[1] = lastBlockSize1;
291
292 if(numCol == blockStart1) // -> test "b"
293 {
294 subSize[1] -= posOut1;
295 subSize[0] = currentBlock->size(0);
296 if(numRow == blockEnd0) // if last row of blocks
297 subSize[0] = lastBlockSize0;
298 if(numRow == blockStart0) // if first row of blocks
299 subSize[0] -= posOut0;
300 }
301
302 // Set sub-block
303 setBlock(currentBlock, output_matrix, subSize, currentPos);
304
305 // Update currentPos:
306 // col position for first element to be read in input_matrix,
307 currentPos[1] = 0 ;
308 // col position for first element to be set in sub-block.
309 currentPos[3] += subSize[1];
310 numCol++;
311 }
312
313 numCol = blockStart1;
314 numRow++;
315
316 // Update currentPos:
317 // row position for first element to be read in input_matrix,
318 currentPos[0] = 0;
319 // col position for first element to be read in input_matrix,
320 currentPos[1] = posOut1;
321 // row position for first element to be set in sub-block.
322 currentPos[2] += subSize[0] ;
323 // col position for first element to be set in sub-block.
324 currentPos[3] = start[3];
325
326 }
327 output_matrix->resetFactorizationFlags();
328
329 }
330 else // neither input_matrix nor output_matrix is a BlockMatrix.
331 {
332 if(numOut == Siconos::DENSE)
333 {
334 ublas::matrix_range<DenseMat> out_range(*output_matrix->dense(),
335 ublas::range(start[2],end[2]),
336 ublas::range(start[3], end[3]));
337 if(numIn == Siconos::DENSE)
338 {
339 ublas::matrix_range<DenseMat> in_range(*input_matrix->dense(),
340 ublas::range(start[0],end[0]),
341 ublas::range(start[1], end[1]));
342 noalias(out_range) = in_range;
343 }
344 else if(numIn == Siconos::SYMMETRIC)
345 {
346 ublas::matrix_range<SymMat> in_range(*input_matrix->sym(),
347 ublas::range(start[0],end[0]),
348 ublas::range(start[1], end[1]));
349 noalias(out_range) = in_range;
350 }
351 else if(numIn == Siconos::SPARSE)
352 {
353 ublas::matrix_range<SparseMat> in_range(*input_matrix->sparse(),
354 ublas::range(start[0],end[0]),
355 ublas::range(start[1], end[1]));
356 noalias(out_range) = in_range;
357 }
358 else if(numIn == Siconos::IDENTITY)
359 {
360 ublas::matrix_range<IdentityMat> in_range(*input_matrix->identity(),
361 ublas::range(start[0],end[0]),
362 ublas::range(start[1], end[1]));
363 noalias(out_range) = in_range;
364 }
365 else if(numIn == Siconos::ZERO)
366 out_range *= 0.;
367 else
368 THROW_EXCEPTION("unconsistent types between input_matrix and output_matrix.");
369 }
370 else if(numOut == Siconos::SPARSE)
371 {
372 ublas::matrix_range<SparseMat> out_range(*output_matrix->sparse(),
373 ublas::range(start[2],end[2]),
374 ublas::range(start[3], end[3]));
375 if(numIn == Siconos::DENSE)
376 {
377 ublas::matrix_range<DenseMat> in_range(*input_matrix->dense(),
378 ublas::range(start[0],end[0]),
379 ublas::range(start[1], end[1]));
380 noalias(out_range) = in_range;
381 }
382 else if(numIn == Siconos::SYMMETRIC)
383 {
384 ublas::matrix_range<SymMat> in_range(*input_matrix->sym(),
385 ublas::range(start[0],end[0]),
386 ublas::range(start[1], end[1]));
387 noalias(out_range) = in_range;
388 }
389 else if(numIn == Siconos::SPARSE)
390 {
391 ublas::matrix_range<SparseMat> in_range(*input_matrix->sparse(),
392 ublas::range(start[0],end[0]),
393 ublas::range(start[1], end[1]));
394 noalias(out_range) = in_range;
395 }
396 else if(numIn == Siconos::IDENTITY)
397 {
398 ublas::matrix_range<IdentityMat> in_range(*input_matrix->identity(),
399 ublas::range(start[0],end[0]),
400 ublas::range(start[1], end[1]));
401 noalias(out_range) = in_range;
402 }
403 else if(numIn == Siconos::ZERO)
404 out_range *= 0.;
405 else
406 THROW_EXCEPTION("unconsistent types between input_matrix and output_matrix.");
407 }
408
409 output_matrix->resetFactorizationFlags();
410 }
411 }
412