1 // SPDX-License-Identifier: Apache-2.0
2 //
3 // Copyright 2008-2016 Conrad Sanderson (http://conradsanderson.id.au)
4 // Copyright 2008-2016 National ICT Australia (NICTA)
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 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 // ------------------------------------------------------------------------
17 
18 
19 //! \addtogroup spglue_relational
20 //! @{
21 
22 
23 
24 template<typename T1, typename T2>
25 inline
26 void
apply(SpMat<uword> & out,const mtSpGlue<uword,T1,T2,spglue_rel_lt> & X)27 spglue_rel_lt::apply(SpMat<uword>& out, const mtSpGlue<uword, T1, T2, spglue_rel_lt>& X)
28   {
29   arma_extra_debug_sigprint();
30 
31   const SpProxy<T1> PA(X.A);
32   const SpProxy<T2> PB(X.B);
33 
34   const bool is_alias = PA.is_alias(out) || PB.is_alias(out);
35 
36   if(is_alias == false)
37     {
38     spglue_rel_lt::apply_noalias(out, PA, PB);
39     }
40   else
41     {
42     SpMat<uword> tmp;
43 
44     spglue_rel_lt::apply_noalias(tmp, PA, PB);
45 
46     out.steal_mem(tmp);
47     }
48   }
49 
50 
51 
52 template<typename T1, typename T2>
53 inline
54 void
apply_noalias(SpMat<uword> & out,const SpProxy<T1> & PA,const SpProxy<T2> & PB)55 spglue_rel_lt::apply_noalias(SpMat<uword>& out, const SpProxy<T1>& PA, const SpProxy<T2>& PB)
56   {
57   arma_extra_debug_sigprint();
58 
59   typedef typename T1::elem_type eT;
60 
61   arma_debug_assert_same_size(PA.get_n_rows(), PA.get_n_cols(), PB.get_n_rows(), PB.get_n_cols(), "operator<");
62 
63   const uword max_n_nonzero = PA.get_n_nonzero() + PB.get_n_nonzero();
64 
65   // Resize memory to upper bound
66   out.reserve(PA.get_n_rows(), PA.get_n_cols(), max_n_nonzero);
67 
68   // Now iterate across both matrices.
69   typename SpProxy<T1>::const_iterator_type x_it  = PA.begin();
70   typename SpProxy<T1>::const_iterator_type x_end = PA.end();
71 
72   typename SpProxy<T2>::const_iterator_type y_it  = PB.begin();
73   typename SpProxy<T2>::const_iterator_type y_end = PB.end();
74 
75   uword count = 0;
76 
77   while( (x_it != x_end) || (y_it != y_end) )
78     {
79     uword out_val;
80 
81     const uword x_it_col = x_it.col();
82     const uword x_it_row = x_it.row();
83 
84     const uword y_it_col = y_it.col();
85     const uword y_it_row = y_it.row();
86 
87     bool use_y_loc = false;
88 
89     if(x_it == y_it)
90       {
91       out_val = ((*x_it) < (*y_it)) ? uword(1) : uword(0);
92 
93       ++x_it;
94       ++y_it;
95       }
96     else
97       {
98       if((x_it_col < y_it_col) || ((x_it_col == y_it_col) && (x_it_row < y_it_row))) // if y is closer to the end
99         {
100         out_val = ((*x_it) < eT(0)) ? uword(1) : uword(0);
101 
102         ++x_it;
103         }
104       else
105         {
106         out_val = (eT(0) < (*y_it)) ? uword(1) : uword(0);
107 
108         ++y_it;
109 
110         use_y_loc = true;
111         }
112       }
113 
114     if(out_val != uword(0))
115       {
116       access::rw(out.values[count]) = out_val;
117 
118       const uword out_row = (use_y_loc == false) ? x_it_row : y_it_row;
119       const uword out_col = (use_y_loc == false) ? x_it_col : y_it_col;
120 
121       access::rw(out.row_indices[count]) = out_row;
122       access::rw(out.col_ptrs[out_col + 1])++;
123       ++count;
124       }
125 
126     arma_check( (count > max_n_nonzero), "internal error: spglue_rel_lt::apply_noalias(): count > max_n_nonzero" );
127     }
128 
129   const uword out_n_cols = out.n_cols;
130 
131   uword* col_ptrs = access::rwp(out.col_ptrs);
132 
133   // Fix column pointers to be cumulative.
134   for(uword c = 1; c <= out_n_cols; ++c)
135     {
136     col_ptrs[c] += col_ptrs[c - 1];
137     }
138 
139   if(count < max_n_nonzero)
140     {
141     if(count <= (max_n_nonzero/2))
142       {
143       out.mem_resize(count);
144       }
145     else
146       {
147       // quick resize without reallocating memory and copying data
148       access::rw(         out.n_nonzero) = count;
149       access::rw(     out.values[count]) = eT(0);
150       access::rw(out.row_indices[count]) = uword(0);
151       }
152     }
153   }
154 
155 
156 
157 //
158 
159 
160 
161 template<typename T1, typename T2>
162 inline
163 void
apply(SpMat<uword> & out,const mtSpGlue<uword,T1,T2,spglue_rel_gt> & X)164 spglue_rel_gt::apply(SpMat<uword>& out, const mtSpGlue<uword, T1, T2, spglue_rel_gt>& X)
165   {
166   arma_extra_debug_sigprint();
167 
168   const SpProxy<T1> PA(X.A);
169   const SpProxy<T2> PB(X.B);
170 
171   const bool is_alias = PA.is_alias(out) || PB.is_alias(out);
172 
173   if(is_alias == false)
174     {
175     spglue_rel_gt::apply_noalias(out, PA, PB);
176     }
177   else
178     {
179     SpMat<uword> tmp;
180 
181     spglue_rel_gt::apply_noalias(tmp, PA, PB);
182 
183     out.steal_mem(tmp);
184     }
185   }
186 
187 
188 
189 template<typename T1, typename T2>
190 inline
191 void
apply_noalias(SpMat<uword> & out,const SpProxy<T1> & PA,const SpProxy<T2> & PB)192 spglue_rel_gt::apply_noalias(SpMat<uword>& out, const SpProxy<T1>& PA, const SpProxy<T2>& PB)
193   {
194   arma_extra_debug_sigprint();
195 
196   typedef typename T1::elem_type eT;
197 
198   arma_debug_assert_same_size(PA.get_n_rows(), PA.get_n_cols(), PB.get_n_rows(), PB.get_n_cols(), "operator>");
199 
200   const uword max_n_nonzero = PA.get_n_nonzero() + PB.get_n_nonzero();
201 
202   // Resize memory to upper bound
203   out.reserve(PA.get_n_rows(), PA.get_n_cols(), max_n_nonzero);
204 
205   // Now iterate across both matrices.
206   typename SpProxy<T1>::const_iterator_type x_it  = PA.begin();
207   typename SpProxy<T1>::const_iterator_type x_end = PA.end();
208 
209   typename SpProxy<T2>::const_iterator_type y_it  = PB.begin();
210   typename SpProxy<T2>::const_iterator_type y_end = PB.end();
211 
212   uword count = 0;
213 
214   while( (x_it != x_end) || (y_it != y_end) )
215     {
216     uword out_val;
217 
218     const uword x_it_col = x_it.col();
219     const uword x_it_row = x_it.row();
220 
221     const uword y_it_col = y_it.col();
222     const uword y_it_row = y_it.row();
223 
224     bool use_y_loc = false;
225 
226     if(x_it == y_it)
227       {
228       out_val = ((*x_it) > (*y_it)) ? uword(1) : uword(0);
229 
230       ++x_it;
231       ++y_it;
232       }
233     else
234       {
235       if((x_it_col < y_it_col) || ((x_it_col == y_it_col) && (x_it_row < y_it_row))) // if y is closer to the end
236         {
237         out_val = ((*x_it) > eT(0)) ? uword(1) : uword(0);
238 
239         ++x_it;
240         }
241       else
242         {
243         out_val = (eT(0) > (*y_it)) ? uword(1) : uword(0);
244 
245         ++y_it;
246 
247         use_y_loc = true;
248         }
249       }
250 
251     if(out_val != uword(0))
252       {
253       access::rw(out.values[count]) = out_val;
254 
255       const uword out_row = (use_y_loc == false) ? x_it_row : y_it_row;
256       const uword out_col = (use_y_loc == false) ? x_it_col : y_it_col;
257 
258       access::rw(out.row_indices[count]) = out_row;
259       access::rw(out.col_ptrs[out_col + 1])++;
260       ++count;
261       }
262 
263     arma_check( (count > max_n_nonzero), "internal error: spglue_rel_gt::apply_noalias(): count > max_n_nonzero" );
264     }
265 
266   const uword out_n_cols = out.n_cols;
267 
268   uword* col_ptrs = access::rwp(out.col_ptrs);
269 
270   // Fix column pointers to be cumulative.
271   for(uword c = 1; c <= out_n_cols; ++c)
272     {
273     col_ptrs[c] += col_ptrs[c - 1];
274     }
275 
276   if(count < max_n_nonzero)
277     {
278     if(count <= (max_n_nonzero/2))
279       {
280       out.mem_resize(count);
281       }
282     else
283       {
284       // quick resize without reallocating memory and copying data
285       access::rw(         out.n_nonzero) = count;
286       access::rw(     out.values[count]) = eT(0);
287       access::rw(out.row_indices[count]) = uword(0);
288       }
289     }
290   }
291 
292 
293 
294 //
295 
296 
297 
298 template<typename T1, typename T2>
299 inline
300 void
apply(SpMat<uword> & out,const mtSpGlue<uword,T1,T2,spglue_rel_and> & X)301 spglue_rel_and::apply(SpMat<uword>& out, const mtSpGlue<uword, T1, T2, spglue_rel_and>& X)
302   {
303   arma_extra_debug_sigprint();
304 
305   const SpProxy<T1> PA(X.A);
306   const SpProxy<T2> PB(X.B);
307 
308   const bool is_alias = PA.is_alias(out) || PB.is_alias(out);
309 
310   if(is_alias == false)
311     {
312     spglue_rel_and::apply_noalias(out, PA, PB);
313     }
314   else
315     {
316     SpMat<uword> tmp;
317 
318     spglue_rel_and::apply_noalias(tmp, PA, PB);
319 
320     out.steal_mem(tmp);
321     }
322   }
323 
324 
325 
326 template<typename T1, typename T2>
327 inline
328 void
apply_noalias(SpMat<uword> & out,const SpProxy<T1> & PA,const SpProxy<T2> & PB)329 spglue_rel_and::apply_noalias(SpMat<uword>& out, const SpProxy<T1>& PA, const SpProxy<T2>& PB)
330   {
331   arma_extra_debug_sigprint();
332 
333   typedef typename T1::elem_type eT;
334 
335   arma_debug_assert_same_size(PA.get_n_rows(), PA.get_n_cols(), PB.get_n_rows(), PB.get_n_cols(), "operator&&");
336 
337   if( (PA.get_n_nonzero() == 0) || (PB.get_n_nonzero() == 0) )
338     {
339     out.zeros(PA.get_n_rows(), PA.get_n_cols());
340     return;
341     }
342 
343   const uword max_n_nonzero = (std::min)(PA.get_n_nonzero(), PB.get_n_nonzero());
344 
345   // Resize memory to upper bound
346   out.reserve(PA.get_n_rows(), PA.get_n_cols(), max_n_nonzero);
347 
348   // Now iterate across both matrices.
349   typename SpProxy<T1>::const_iterator_type x_it  = PA.begin();
350   typename SpProxy<T1>::const_iterator_type x_end = PA.end();
351 
352   typename SpProxy<T2>::const_iterator_type y_it  = PB.begin();
353   typename SpProxy<T2>::const_iterator_type y_end = PB.end();
354 
355   uword count = 0;
356 
357   while( (x_it != x_end) || (y_it != y_end) )
358     {
359     const uword x_it_row = x_it.row();
360     const uword x_it_col = x_it.col();
361 
362     const uword y_it_row = y_it.row();
363     const uword y_it_col = y_it.col();
364 
365     if(x_it == y_it)
366       {
367       access::rw(out.values[count]) = uword(1);
368 
369       access::rw(out.row_indices[count]) = x_it_row;
370       access::rw(out.col_ptrs[x_it_col + 1])++;
371       ++count;
372 
373       ++x_it;
374       ++y_it;
375       }
376     else
377       {
378       if((x_it_col < y_it_col) || ((x_it_col == y_it_col) && (x_it_row < y_it_row))) // if y is closer to the end
379         {
380         ++x_it;
381         }
382       else
383         {
384         ++y_it;
385         }
386       }
387 
388     arma_check( (count > max_n_nonzero), "internal error: spglue_rel_and::apply_noalias(): count > max_n_nonzero" );
389     }
390 
391   const uword out_n_cols = out.n_cols;
392 
393   uword* col_ptrs = access::rwp(out.col_ptrs);
394 
395   // Fix column pointers to be cumulative.
396   for(uword c = 1; c <= out_n_cols; ++c)
397     {
398     col_ptrs[c] += col_ptrs[c - 1];
399     }
400 
401   if(count < max_n_nonzero)
402     {
403     if(count <= (max_n_nonzero/2))
404       {
405       out.mem_resize(count);
406       }
407     else
408       {
409       // quick resize without reallocating memory and copying data
410       access::rw(         out.n_nonzero) = count;
411       access::rw(     out.values[count]) = eT(0);
412       access::rw(out.row_indices[count]) = uword(0);
413       }
414     }
415   }
416 
417 
418 
419 //
420 
421 
422 
423 template<typename T1, typename T2>
424 inline
425 void
apply(SpMat<uword> & out,const mtSpGlue<uword,T1,T2,spglue_rel_or> & X)426 spglue_rel_or::apply(SpMat<uword>& out, const mtSpGlue<uword, T1, T2, spglue_rel_or>& X)
427   {
428   arma_extra_debug_sigprint();
429 
430   const SpProxy<T1> PA(X.A);
431   const SpProxy<T2> PB(X.B);
432 
433   const bool is_alias = PA.is_alias(out) || PB.is_alias(out);
434 
435   if(is_alias == false)
436     {
437     spglue_rel_or::apply_noalias(out, PA, PB);
438     }
439   else
440     {
441     SpMat<uword> tmp;
442 
443     spglue_rel_or::apply_noalias(tmp, PA, PB);
444 
445     out.steal_mem(tmp);
446     }
447   }
448 
449 
450 
451 template<typename T1, typename T2>
452 inline
453 void
apply_noalias(SpMat<uword> & out,const SpProxy<T1> & PA,const SpProxy<T2> & PB)454 spglue_rel_or::apply_noalias(SpMat<uword>& out, const SpProxy<T1>& PA, const SpProxy<T2>& PB)
455   {
456   arma_extra_debug_sigprint();
457 
458   typedef typename T1::elem_type eT;
459 
460   arma_debug_assert_same_size(PA.get_n_rows(), PA.get_n_cols(), PB.get_n_rows(), PB.get_n_cols(), "operator||");
461 
462   const uword max_n_nonzero = PA.get_n_nonzero() + PB.get_n_nonzero();
463 
464   // Resize memory to upper bound
465   out.reserve(PA.get_n_rows(), PA.get_n_cols(), max_n_nonzero);
466 
467   // Now iterate across both matrices.
468   typename SpProxy<T1>::const_iterator_type x_it  = PA.begin();
469   typename SpProxy<T1>::const_iterator_type x_end = PA.end();
470 
471   typename SpProxy<T2>::const_iterator_type y_it  = PB.begin();
472   typename SpProxy<T2>::const_iterator_type y_end = PB.end();
473 
474   uword count = 0;
475 
476   while( (x_it != x_end) || (y_it != y_end) )
477     {
478     const uword x_it_col = x_it.col();
479     const uword x_it_row = x_it.row();
480 
481     const uword y_it_col = y_it.col();
482     const uword y_it_row = y_it.row();
483 
484     bool use_y_loc = false;
485 
486     if(x_it == y_it)
487       {
488       ++x_it;
489       ++y_it;
490       }
491     else
492       {
493       if((x_it_col < y_it_col) || ((x_it_col == y_it_col) && (x_it_row < y_it_row))) // if y is closer to the end
494         {
495         ++x_it;
496         }
497       else
498         {
499         ++y_it;
500 
501         use_y_loc = true;
502         }
503       }
504 
505     access::rw(out.values[count]) = uword(1);
506 
507     const uword out_row = (use_y_loc == false) ? x_it_row : y_it_row;
508     const uword out_col = (use_y_loc == false) ? x_it_col : y_it_col;
509 
510     access::rw(out.row_indices[count]) = out_row;
511     access::rw(out.col_ptrs[out_col + 1])++;
512     ++count;
513 
514     arma_check( (count > max_n_nonzero), "internal error: spglue_rel_or::apply_noalias(): count > max_n_nonzero" );
515     }
516 
517   const uword out_n_cols = out.n_cols;
518 
519   uword* col_ptrs = access::rwp(out.col_ptrs);
520 
521   // Fix column pointers to be cumulative.
522   for(uword c = 1; c <= out_n_cols; ++c)
523     {
524     col_ptrs[c] += col_ptrs[c - 1];
525     }
526 
527   if(count < max_n_nonzero)
528     {
529     if(count <= (max_n_nonzero/2))
530       {
531       out.mem_resize(count);
532       }
533     else
534       {
535       // quick resize without reallocating memory and copying data
536       access::rw(         out.n_nonzero) = count;
537       access::rw(     out.values[count]) = eT(0);
538       access::rw(out.row_indices[count]) = uword(0);
539       }
540     }
541   }
542 
543 
544 
545 //! @}
546