1 //-----------------------------------------------------------------------bl-
2 //--------------------------------------------------------------------------
3 //
4 // MetaPhysicL - A metaprogramming library for physics calculations
5 //
6 // Copyright (C) 2013 The PECOS Development Team
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the Version 2.1 GNU Lesser General
10 // Public License as published by the Free Software Foundation.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // Lesser General Public License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public
18 // License along with this library; if not, write to the Free Software
19 // Foundation, Inc. 51 Franklin Street, Fifth Floor,
20 // Boston, MA 02110-1301 USA
21 //
22 //-----------------------------------------------------------------------el-
23 //
24 // $Id: core.h 37197 2013-02-21 05:49:09Z roystgnr $
25 //
26 //--------------------------------------------------------------------------
27
28
29 #ifndef METAPHYSICL_DYNAMICSPARSENUMBERBASE_H
30 #define METAPHYSICL_DYNAMICSPARSENUMBERBASE_H
31
32 #include "metaphysicl/dynamicsparsenumberbase_decl.h"
33
34 namespace MetaPhysicL {
35
36 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
37 inline
38 std::size_t
size()39 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::size() const
40 { metaphysicl_assert_equal_to(_data.size(), _indices.size());
41 return _data.size(); }
42
43 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
44 inline
45 void
resize(std::size_t s)46 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::resize(std::size_t s)
47 { metaphysicl_assert_equal_to(_data.size(), _indices.size());
48 _data.resize(s);
49 _indices.resize(s); }
50
51 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
52 inline
DynamicSparseNumberBase()53 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::DynamicSparseNumberBase() {}
54
55 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
56 template <typename Data2, typename Indices2, class... SubTypeArgs2>
57 inline
58 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::
DynamicSparseNumberBase(const DynamicSparseNumberBase<Data2,Indices2,SubType,SubTypeArgs2...> & src)59 DynamicSparseNumberBase(const DynamicSparseNumberBase<Data2, Indices2, SubType, SubTypeArgs2...> & src)
60 { this->resize(src.size());
61 std::copy(src.nude_data().begin(), src.nude_data().end(), _data.begin());
62 std::copy(src.nude_indices().begin(), src.nude_indices().end(), _indices.begin()); }
63
64 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
65 template <typename Data2, typename Indices2, class... SubTypeArgs2>
DynamicSparseNumberBase(DynamicSparseNumberBase<Data2,Indices2,SubType,SubTypeArgs2...> && src)66 inline DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::DynamicSparseNumberBase(
67 DynamicSparseNumberBase<Data2, Indices2, SubType, SubTypeArgs2...> && src)
68 {
69 _data = std::move(src.nude_data());
70 _indices = std::move(src.nude_indices());
71 }
72
73 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
74 inline
75 typename Data::value_type*
raw_data()76 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::raw_data()
77 { return size()?&_data[0]:NULL; }
78
79 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
80 inline
81 const typename Data::value_type*
raw_data()82 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::raw_data() const
83 { return size()?&_data[0]:NULL; }
84
85 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
86 inline
87 typename Data::reference
raw_at(unsigned int i)88 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::raw_at(unsigned int i)
89 { return _data[i]; }
90
91 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
92 inline
93 typename Data::const_reference
raw_at(unsigned int i)94 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::raw_at(unsigned int i) const
95 { return _data[i]; }
96
97 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
98 inline
99 typename Indices::value_type&
raw_index(unsigned int i)100 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::raw_index(unsigned int i)
101 { return _indices[i]; }
102
103 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
104 inline
105 const typename Indices::value_type &
raw_index(unsigned int i)106 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::raw_index(unsigned int i) const
107 { return _indices[i]; }
108
109 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
110 inline
111 const Data&
nude_data()112 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::nude_data() const
113 { return _data; }
114
115 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
116 inline
117 Data&
nude_data()118 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::nude_data()
119 { return _data; }
120
121 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
122 inline
123 const Indices&
nude_indices()124 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::nude_indices() const
125 { return _indices; }
126
127 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
128 inline
129 Indices&
nude_indices()130 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::nude_indices()
131 { return _indices; }
132
133 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
134 inline
135 std::size_t
runtime_index_query(index_value_type i)136 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::runtime_index_query(index_value_type i) const
137 {
138 auto it =
139 std::lower_bound(_indices.begin(), _indices.end(), i);
140 if (it == _indices.end() || *it != i)
141 return std::numeric_limits<std::size_t>::max();
142 std::size_t offset = it - _indices.begin();
143 metaphysicl_assert_equal_to(_indices[offset], i);
144 return offset;
145 }
146
147 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
148 inline
149 std::size_t
runtime_index_of(index_value_type i)150 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::runtime_index_of(index_value_type i) const
151 {
152 auto it =
153 std::lower_bound(_indices.begin(), _indices.end(), i);
154 metaphysicl_assert(it != _indices.end());
155 std::size_t offset = it - _indices.begin();
156 metaphysicl_assert_equal_to(_indices[offset], i);
157 return offset;
158 }
159
160 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
161 inline
162 typename Data::value_type &
163 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::operator[](index_value_type i)
164 {
165 typedef typename Data::value_type T;
166 static T zero = 0;
167
168 // Bad user code could make this fail. We'd prefer to catch OOB
169 // writes at *write* time but at least we can catch at read time.
170 metaphysicl_assert(zero == T(0));
171
172 std::size_t rq = runtime_index_query(i);
173 if (rq == std::numeric_limits<std::size_t>::max())
174 return zero;
175 return _data[rq];
176 }
177
178 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
179 inline
180 const typename Data::value_type&
181 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::operator[](index_value_type i) const
182 {
183 typedef typename Data::value_type T;
184 static const T zero = 0;
185 std::size_t rq = runtime_index_query(i);
186 if (rq == std::numeric_limits<std::size_t>::max())
187 return zero;
188 return _data[rq];
189 }
190
191 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
192 template <unsigned int i>
193 inline
194 typename DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::template entry_type<i>::type&
get()195 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::get() {
196 return _data[runtime_index_of(i)];
197 }
198
199 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
200 template <unsigned int i>
201 inline
202 const typename DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::template entry_type<i>::type&
get()203 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::get() const {
204 return _data[runtime_index_of(i)];
205 }
206
207 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
208 inline
209 typename DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::value_type&
insert(unsigned int i)210 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::insert(unsigned int i)
211 {
212 auto upper_it =
213 std::lower_bound(_indices.begin(), _indices.end(), i);
214 std::size_t offset = upper_it - _indices.begin();
215
216 // If we don't have entry i, insert it. Yes this is O(N).
217 if ((upper_it == _indices.end()) ||
218 *upper_it != i)
219 {
220 std::size_t old_size = this->size();
221 this->resize(old_size+1);
222 std::copy_backward(_indices.begin()+offset, _indices.begin()+old_size, _indices.end());
223 std::copy_backward(_data.begin()+offset, _data.begin()+old_size, _data.end());
224 _indices[offset] = i;
225 _data[offset] = 0;
226 }
227
228 // We have entry i now; return it
229 return _data[offset];
230 }
231
232 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
233 template <unsigned int i>
234 inline
235 typename DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::template entry_type<i>::type&
insert()236 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::insert() {
237 return this->insert(i);
238 }
239
240 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
241 template <unsigned int i, typename T2>
242 inline
243 void
set(const T2 & val)244 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::set(const T2& val) {
245 _data[runtime_index_of(i)] = val;
246 }
247
248 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
249 inline
250 bool
boolean_test()251 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::boolean_test() const {
252 std::size_t index_size = size();
253 for (unsigned int i=0; i != index_size; ++i)
254 if (_data[i])
255 return true;
256 return false;
257 }
258
259 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
260 inline
261 SubType<SubTypeArgs...>
262 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::operator- () const {
263 std::size_t index_size = size();
264 SubType<SubTypeArgs...> returnval;
265 returnval.resize(index_size);
266 for (unsigned int i=0; i != index_size; ++i)
267 {
268 returnval.raw_index(i) = _indices[i];
269 returnval.raw_at(i) = -_data[i];
270 }
271 return returnval;
272 }
273
274 // Since this is a dynamically allocated sparsity pattern, we can
275 // increase it as needed to support e.g. operator+=
276 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
277 template <typename Indices2>
278 inline
279 void
sparsity_union(const Indices2 & new_indices)280 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::sparsity_union (const Indices2 & new_indices)
281 {
282 metaphysicl_assert
283 (std::adjacent_find(_indices.begin(), _indices.end()) ==
284 _indices.end());
285 metaphysicl_assert
286 (std::adjacent_find(new_indices.begin(), new_indices.end()) ==
287 new_indices.end());
288 #ifdef METAPHYSICL_HAVE_CXX11
289 metaphysicl_assert(std::is_sorted(_indices.begin(), _indices.end()));
290 metaphysicl_assert(std::is_sorted(new_indices.begin(), new_indices.end()));
291 #endif
292
293 auto index_it = _indices.begin();
294 auto index2_it = new_indices.begin();
295
296 typedef typename Indices2::value_type I2;
297 typedef typename CompareTypes<I,I2>::supertype max_index_type;
298 max_index_type unseen_indices = 0;
299
300 const I maxI = std::numeric_limits<I>::max();
301
302 while (index2_it != new_indices.end()) {
303 I idx1 = (index_it == _indices.end()) ? maxI : *index_it;
304 I2 idx2 = *index2_it;
305
306 while (idx1 < idx2) {
307 ++index_it;
308 idx1 = (index_it == _indices.end()) ? maxI : *index_it;
309 }
310
311 while ((idx1 == idx2) &&
312 (idx1 != maxI)) {
313 ++index_it;
314 idx1 = (index_it == _indices.end()) ? maxI : *index_it;
315 ++index2_it;
316 idx2 = (index2_it == new_indices.end()) ? maxI : *index2_it;
317 }
318
319 while (idx2 < idx1) {
320 ++unseen_indices;
321 ++index2_it;
322 if (index2_it == new_indices.end())
323 break;
324 idx2 = *index2_it;
325 }
326 }
327
328 // The common case is cheap
329 if (!unseen_indices)
330 return;
331
332 std::size_t old_size = this->size();
333
334 this->resize(old_size + unseen_indices);
335
336 auto md_it = _data.rbegin();
337 auto mi_it = _indices.rbegin();
338
339 auto d_it =
340 _data.rbegin() + unseen_indices;
341 auto i_it =
342 _indices.rbegin() + unseen_indices;
343 auto i2_it = new_indices.rbegin();
344
345 // Duplicate copies of rend() to work around
346 // http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#179
347 auto mirend = _indices.rend();
348 auto rend = mirend;
349 auto rend2 = new_indices.rend();
350 #ifndef NDEBUG
351 auto mdrend = _data.rend();
352 auto drend = mdrend;
353 #endif
354
355 for (; mi_it != mirend; ++md_it, ++mi_it) {
356 if ((i_it == rend) ||
357 ((i2_it != rend2) &&
358 (*i2_it > *i_it))) {
359 *md_it = 0;
360 *mi_it = *i2_it;
361 ++i2_it;
362 } else {
363 if ((i2_it != rend2) &&
364 (*i2_it == *i_it))
365 ++i2_it;
366 metaphysicl_assert(d_it < drend);
367 metaphysicl_assert(md_it < mdrend);
368 *md_it = *d_it;
369 *mi_it = *i_it;
370 ++d_it;
371 ++i_it;
372 }
373 }
374
375 metaphysicl_assert(i_it == rend);
376 metaphysicl_assert(i2_it == rend2);
377 metaphysicl_assert(d_it == drend);
378 metaphysicl_assert(md_it == mdrend);
379 }
380
381
382 // Since this is a dynamically allocated sparsity pattern, we can
383 // decrease it when possible for efficiency
384 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
385 template <typename Indices2>
386 inline
387 void
388 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::
sparsity_intersection(const Indices2 & new_indices)389 sparsity_intersection (const Indices2 & new_indices)
390 {
391 metaphysicl_assert
392 (std::adjacent_find(_indices.begin(), _indices.end()) ==
393 _indices.end());
394 metaphysicl_assert
395 (std::adjacent_find(new_indices.begin(), new_indices.end()) ==
396 new_indices.end());
397 #ifdef METAPHYSICL_HAVE_CXX11
398 metaphysicl_assert(std::is_sorted(_indices.begin(), _indices.end()));
399 metaphysicl_assert(std::is_sorted(new_indices.begin(), new_indices.end()));
400 #endif
401
402 #ifndef NDEBUG
403 typedef typename Indices2::value_type I2;
404 typedef typename CompareTypes<I,I2>::supertype max_index_type;
405 auto index_it = _indices.begin();
406 auto index2_it = new_indices.begin();
407
408 max_index_type shared_indices = 0;
409
410 const I maxI = std::numeric_limits<I>::max();
411
412 while (index2_it != new_indices.end()) {
413 I idx1 = (index_it == _indices.end()) ? maxI : *index_it;
414 I2 idx2 = *index2_it;
415
416 while (idx1 < idx2) {
417 ++index_it;
418 idx1 = (index_it == _indices.end()) ? maxI : *index_it;
419 }
420
421 while ((idx1 == idx2) &&
422 (idx1 != maxI)) {
423 ++index_it;
424 idx1 = (index_it == _indices.end()) ? maxI : *index_it;
425 ++index2_it;
426 idx2 = (index2_it == new_indices.end()) ? maxI : *index2_it;
427 ++shared_indices;
428 }
429
430 while (idx2 < idx1) {
431 ++index2_it;
432 if (index2_it == new_indices.end())
433 break;
434 idx2 = *index2_it;
435 }
436 }
437 #endif
438
439 // We'll loop up through the arrays, copying indices (and
440 // corresponding data) that should be there downward into place.
441
442 // Merged values:
443 auto md_it = _data.begin();
444 auto mi_it = _indices.begin();
445
446 // Our old values:
447 auto d_it = _data.begin();
448 auto i_it = _indices.begin();
449
450 // Values to merge with:
451 auto i2_it = new_indices.begin();
452
453 for (; i_it != _indices.end() && i2_it != new_indices.end();
454 ++md_it, ++mi_it, ++d_it, ++i_it, ++i2_it) {
455 while (*i2_it < *i_it) {
456 ++i2_it;
457 if (i2_it == new_indices.end())
458 break;
459 }
460 if (i2_it == new_indices.end())
461 break;
462 while (*i2_it > *i_it) {
463 ++i_it;
464 if (i_it == _indices.end())
465 break;
466 }
467 if (i_it == _indices.end())
468 break;
469
470 *md_it = *d_it;
471 *mi_it = *i_it;
472 }
473
474 metaphysicl_assert_equal_to(md_it - _data.begin(),
475 shared_indices);
476 metaphysicl_assert_equal_to(mi_it - _indices.begin(),
477 shared_indices);
478
479 const std::size_t n_indices = md_it - _data.begin();
480
481 _indices.resize(n_indices);
482 _data.resize(n_indices);
483 }
484
485
486
487 // Since this is a dynamically allocated sparsity pattern, we can
488 // decrease it when possible for efficiency
489 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
490 inline
491 void
sparsity_trim()492 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::sparsity_trim ()
493 {
494 metaphysicl_assert
495 (std::adjacent_find(_indices.begin(), _indices.end()) ==
496 _indices.end());
497 #ifdef METAPHYSICL_HAVE_CXX11
498 metaphysicl_assert(std::is_sorted(_indices.begin(), _indices.end()));
499 #endif
500
501 #ifndef NDEBUG
502 I used_indices = 0;
503
504 {
505 auto index_it = _indices.begin();
506 auto data_it = _data.begin();
507 for (; index_it != _indices.end(); ++index_it, ++data_it)
508 if (*data_it)
509 ++used_indices;
510 }
511 #endif
512
513 // We'll loop up through the arrays, copying indices (and
514 // corresponding data) that should be there downward into place.
515
516 // Downward-merged values:
517 auto md_it = _data.begin();
518 auto mi_it = _indices.begin();
519
520 // Our old values:
521 auto d_it = _data.begin();
522
523 for (auto i_it = _indices.begin();
524 i_it != _indices.end(); ++i_it, ++d_it)
525 if (*d_it)
526 {
527 *mi_it = *i_it;
528 *md_it = *d_it;
529 ++mi_it;
530 ++md_it;
531 }
532
533 const std::size_t n_indices = md_it - _data.begin();
534
535 metaphysicl_assert_equal_to(n_indices, used_indices);
536 metaphysicl_assert_equal_to(mi_it - _indices.begin(),
537 used_indices);
538
539 _indices.resize(n_indices);
540 _data.resize(n_indices);
541 }
542
543 // Not defineable since !0 != 0
544 // SubType<SubTypeArgs...> operator! () const;
545
546 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
547 template <class... SubTypeArgs2>
548 inline
549 SubType<SubTypeArgs...>&
550 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::operator+= (const SubType<SubTypeArgs2...>& a)
551 {
552 // Resize if necessary
553 this->sparsity_union(a.nude_indices());
554
555 auto data_it = _data.begin();
556 auto index_it = _indices.begin();
557 auto data2_it =
558 a.nude_data().begin();
559 auto index2_it =
560 a.nude_indices().begin();
561 for (; data2_it != a.nude_data().end(); ++data2_it, ++index2_it)
562 {
563 auto idx1 = *index_it;
564 auto idx2 = *index2_it;
565
566 while (idx1 < idx2) {
567 ++index_it;
568 ++data_it;
569 metaphysicl_assert(index_it != _indices.end());
570 idx1 = *index_it;
571 }
572 metaphysicl_assert_equal_to(idx1, idx2);
573
574 *data_it += *data2_it;
575 }
576
577 return static_cast<SubType<SubTypeArgs...>&>(*this);
578 }
579
580
581 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
582 template <class... SubTypeArgs2>
583 inline
584 SubType<SubTypeArgs...>&
585 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::operator-= (const SubType<SubTypeArgs2...>& a)
586 {
587 // Resize if necessary
588 this->sparsity_union(a.nude_indices());
589
590 auto data_it = _data.begin();
591 auto index_it = _indices.begin();
592 auto data2_it =
593 a.nude_data().begin();
594 auto index2_it =
595 a.nude_indices().begin();
596 for (; data2_it != a.nude_data().end(); ++data2_it, ++index2_it)
597 {
598 auto idx1 = *index_it;
599 auto idx2 = *index2_it;
600
601 while (idx1 < idx2) {
602 ++index_it;
603 ++data_it;
604 metaphysicl_assert(index_it != _indices.end());
605 idx1 = *index_it;
606 }
607 metaphysicl_assert_equal_to(idx1, idx2);
608
609 *data_it -= *data2_it;
610 }
611
612 return static_cast<SubType<SubTypeArgs...>&>(*this);
613 }
614
615
616 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
617 template <class... SubTypeArgs2>
618 inline
619 SubType<SubTypeArgs...>&
620 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::operator*= (const SubType<SubTypeArgs2...>& a)
621 {
622 // Resize if possible
623 this->sparsity_intersection(a.nude_indices());
624
625 auto data_it = _data.begin();
626 auto index_it = _indices.begin();
627 auto data2_it =
628 a.nude_data().begin();
629 auto index2_it =
630 a.nude_indices().begin();
631 for (; data2_it != a.nude_data().end(); ++data2_it, ++index2_it)
632 {
633 auto idx1 = *index_it;
634 auto idx2 = *index2_it;
635
636 while (idx1 < idx2) {
637 ++index_it;
638 ++data_it;
639 metaphysicl_assert(index_it != _indices.end());
640 idx1 = *index_it;
641 }
642
643 if (idx1 == idx2)
644 *data_it *= *data2_it;
645 }
646
647 return static_cast<SubType<SubTypeArgs...>&>(*this);
648 }
649
650
651 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
652 template <class... SubTypeArgs2>
653 inline
654 SubType<SubTypeArgs...>&
655 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::operator/= (const SubType<SubTypeArgs2...>& a)
656 {
657 auto data_it = _data.begin();
658 auto index_it = _indices.begin();
659 auto data2_it =
660 a.nude_data().begin();
661 auto index2_it =
662 a.nude_indices().begin();
663 for (; data2_it != a.nude_data().end(); ++data2_it, ++index2_it)
664 {
665 auto idx1 = *index_it;
666 auto idx2 = *index2_it;
667
668 while (idx1 < idx2) {
669 ++index_it;
670 ++data_it;
671 metaphysicl_assert(index_it != _indices.end());
672 idx1 = *index_it;
673 }
674
675 if (idx1 == idx2)
676 *data_it /= *data2_it;
677 }
678
679 return static_cast<SubType<SubTypeArgs...>&>(*this);
680 }
681
682
683 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
684 template <typename T2>
685 inline
686 SubType<SubTypeArgs...>&
687 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::operator*= (const T2& a)
688 {
689 std::size_t index_size = size();
690 for (unsigned int i=0; i != index_size; ++i)
691 _data[i] *= a;
692 return static_cast<SubType<SubTypeArgs...>&>(*this);
693 }
694
695 template <typename Data, typename Indices, template <class...> class SubType, class... SubTypeArgs>
696 template <typename T2>
697 inline
698 SubType<SubTypeArgs...>&
699 DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>::operator/= (const T2& a)
700 {
701 std::size_t index_size = size();
702 for (unsigned int i=0; i != index_size; ++i)
703 _data[i] /= a;
704 return static_cast<SubType<SubTypeArgs...>&>(*this);
705 }
706
707 //
708 // Non-member functions
709 //
710
711 template <template <class...> class SubType,
712 typename BoolData,
713 typename BoolIndices,
714 class... BoolSubTypeArgs,
715 typename Data,
716 typename Indices,
717 class... SubTypeArgs,
718 typename Data2,
719 typename Indices2,
720 class... SubTypeArgs2>
721 inline typename SubType<SubTypeArgs...>::template rebind<
722 typename CompareTypes<typename Data::value_type, typename Data2::value_type>::supertype,
723 typename CompareTypes<typename Indices::value_type,
724 typename Indices2::value_type>::supertype>::other
if_else(const DynamicSparseNumberBase<BoolData,BoolIndices,SubType,BoolSubTypeArgs...> & condition,const DynamicSparseNumberBase<Data,Indices,SubType,SubTypeArgs...> & if_true,const DynamicSparseNumberBase<Data2,Indices2,SubType,SubTypeArgs2...> & if_false)725 if_else(
726 const DynamicSparseNumberBase<BoolData, BoolIndices, SubType, BoolSubTypeArgs...> & condition,
727 const DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...> & if_true,
728 const DynamicSparseNumberBase<Data2, Indices2, SubType, SubTypeArgs2...> & if_false)
729 {
730 metaphysicl_assert
731 (std::adjacent_find(condition.nude_indices().begin(), condition.nude_indices().end()) ==
732 condition.nude_indices().end());
733 metaphysicl_assert
734 (std::adjacent_find(if_true.nude_indices().begin(), if_true.nude_indices().end()) ==
735 if_true.nude_indices().end());
736 metaphysicl_assert
737 (std::adjacent_find(if_false.nude_indices().begin(), if_false.nude_indices().end()) ==
738 if_false.nude_indices().end());
739 #ifdef METAPHYSICL_HAVE_CXX11
740 metaphysicl_assert(std::is_sorted(condition.nude_indices().begin(), condition.nude_indices().end()));
741 metaphysicl_assert(std::is_sorted(if_true.nude_indices().begin(), if_true.nude_indices().end()));
742 metaphysicl_assert(std::is_sorted(if_false.nude_indices().begin(), if_false.nude_indices().end()));
743 #endif
744
745 typedef
746 typename CompareTypes<typename Data::value_type, typename Data2::value_type>::supertype TS;
747 typedef
748 typename CompareTypes<typename Indices::value_type, typename Indices2::value_type>::supertype
749 IS;
750
751 typename SubType<SubTypeArgs...>::template rebind<TS, IS>::other returnval;
752
753 // First count returnval size
754 IS required_size = 0;
755 {
756 auto indexcond_it = condition.nude_indices().begin();
757 auto datacond_it = condition.nude_data().begin();
758 auto indextrue_it = if_true.nude_indices().begin();
759 const auto endtrue_it = if_true.nude_indices().end();
760 auto datatrue_it = if_true.nude_data().begin();
761 auto indexfalse_it = if_false.nude_indices().begin();
762 const auto endfalse_it = if_false.nude_indices().end();
763 auto datafalse_it = if_false.nude_data().begin();
764
765 for (; indexcond_it != condition.nude_indices().end(); ++indexcond_it, ++datacond_it)
766 {
767 while (indexfalse_it != endfalse_it &&
768 *indexfalse_it < *indexcond_it)
769 {
770 if (*datafalse_it)
771 ++required_size;
772
773 ++indexfalse_it;
774 ++datafalse_it;
775 }
776
777 if (*datacond_it)
778 {
779 while (indextrue_it != endtrue_it &&
780 *indextrue_it < *indexcond_it)
781 {
782 ++indextrue_it;
783 ++datatrue_it;
784 }
785 if (indextrue_it != endtrue_it &&
786 *indextrue_it == *indexcond_it &&
787 *datatrue_it)
788 {
789 ++required_size;
790 ++indextrue_it;
791 ++datatrue_it;
792 }
793 if (*indexfalse_it == *indexcond_it)
794 {
795 ++indexfalse_it;
796 ++datafalse_it;
797 }
798 }
799 else
800 {
801 if (indexfalse_it != endfalse_it &&
802 *indexfalse_it == *indexcond_it &&
803 *datafalse_it)
804 {
805 ++required_size;
806 ++indexfalse_it;
807 ++datafalse_it;
808 }
809 }
810 }
811 }
812
813 // Then fill returnval
814 returnval.resize(required_size);
815 {
816 auto indexcond_it = condition.nude_indices().begin();
817 auto datacond_it = condition.nude_data().begin();
818 auto indextrue_it = if_true.nude_indices().begin();
819 const auto endtrue_it = if_true.nude_indices().end();
820 auto datatrue_it = if_true.nude_data().begin();
821 auto indexfalse_it = if_false.nude_indices().begin();
822 const auto endfalse_it = if_false.nude_indices().end();
823 auto datafalse_it = if_false.nude_data().begin();
824
825 auto indexreturn_it = returnval.nude_indices().begin();
826 auto datareturn_it = returnval.nude_data().begin();
827
828 for (; indexcond_it != condition.nude_indices().end(); ++indexcond_it, ++datacond_it)
829 {
830 while (indexfalse_it != endfalse_it &&
831 *indexfalse_it < *indexcond_it)
832 {
833 if (*datafalse_it)
834 {
835 *indexreturn_it = *indexfalse_it;
836 *datareturn_it = *datafalse_it;
837 ++indexreturn_it;
838 ++datareturn_it;
839 }
840
841 ++indexfalse_it;
842 ++datafalse_it;
843 }
844
845 if (*datacond_it)
846 {
847 while (indextrue_it != endtrue_it &&
848 *indextrue_it < *indexcond_it)
849 {
850 ++indextrue_it;
851 ++datatrue_it;
852 }
853 if (indextrue_it != endtrue_it &&
854 *indextrue_it == *indexcond_it &&
855 *datatrue_it)
856 {
857 *indexreturn_it = *indextrue_it;
858 *datareturn_it = *datatrue_it;
859 ++indexreturn_it;
860 ++datareturn_it;
861 ++indextrue_it;
862 ++datatrue_it;
863 }
864 if (*indexfalse_it == *indexcond_it)
865 {
866 ++indexfalse_it;
867 ++datafalse_it;
868 }
869 }
870 else
871 {
872 if (indexfalse_it != endfalse_it &&
873 *indexfalse_it == *indexcond_it &&
874 *datafalse_it)
875 {
876 *indexreturn_it = *indexfalse_it;
877 *datareturn_it = *datafalse_it;
878 ++indexreturn_it;
879 ++datareturn_it;
880 ++indexfalse_it;
881 ++datafalse_it;
882 }
883 }
884 }
885 }
886
887 metaphysicl_assert
888 (std::adjacent_find(returnval.nude_indices().begin(), returnval.nude_indices().end()) ==
889 returnval.nude_indices().end());
890 #ifdef METAPHYSICL_HAVE_CXX11
891 metaphysicl_assert(std::is_sorted(returnval.nude_indices().begin(), returnval.nude_indices().end()));
892 #endif
893
894 return returnval;
895 }
896
897
898
899 #define DynamicSparseNumberBase_op_ab(opname, subtypename, functorname) \
900 template <class... AArgs, class... BArgs> \
901 inline \
902 typename Symmetric##functorname##Type<subtypename<AArgs...>, \
903 subtypename<BArgs...>>::supertype \
904 operator opname (const subtypename<AArgs...> & a, const subtypename<BArgs...> & b) \
905 { \
906 typedef typename Symmetric##functorname##Type<subtypename<AArgs...>, \
907 subtypename<BArgs...>>::supertype type; \
908 type returnval = a; \
909 returnval opname##= b; \
910 return returnval; \
911 }
912
913
914 #if __cplusplus >= 201103L
915
916 #define DynamicSparseNumberBase_op(subtypename, opname, functorname) \
917 DynamicSparseNumberBase_op_ab(opname, subtypename, functorname) \
918 \
919 template <class... AArgs, class... BArgs> \
920 inline typename Symmetric##functorname##Type<subtypename<AArgs...>, \
921 subtypename<BArgs...>>::supertype \
922 operator opname(subtypename<AArgs...> && a, const subtypename<BArgs...> & b) \
923 { \
924 typedef typename Symmetric##functorname##Type<subtypename<AArgs...>, \
925 subtypename<BArgs...>>::supertype type; \
926 type returnval = std::move(a); \
927 returnval opname##= b; \
928 return returnval; \
929 }
930
931 #else
932
933 #define DynamicSparseNumberBase_op(subtypename, opname, functorname) \
934 DynamicSparseNumberBase_op_ab(opname, subtypename, functorname)
935
936 #endif
937
938 // Let's also allow scalar times vector.
939 // Scalar plus vector, etc. remain undefined in the sparse context.
940
941 template <template <class...> class SubType,
942 typename Data,
943 typename Indices,
944 class... SubTypeArgs,
945 typename T>
946 inline typename MultipliesType<SubType<SubTypeArgs...>, T, true>::supertype
947 operator*(const T & a, const DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...> & b)
948 {
949 const unsigned int index_size = b.size();
950
951 typename MultipliesType<SubType<SubTypeArgs...>,T,true>::supertype
952 returnval;
953 returnval.resize(index_size);
954
955 for (unsigned int i=0; i != index_size; ++i) {
956 returnval.raw_at(i) = a * b.raw_at(i);
957 returnval.raw_index(i) = b.raw_index(i);
958 }
959
960 return returnval;
961 }
962
963 template <template <class...> class SubType,
964 typename Data,
965 typename Indices,
966 class... SubTypeArgs,
967 typename T>
968 inline typename MultipliesType<SubType<SubTypeArgs...>, T>::supertype
969 operator*(const DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...> & a, const T & b)
970 {
971 const unsigned int index_size = a.size();
972
973 typename MultipliesType<SubType<SubTypeArgs...>,T>::supertype
974 returnval;
975 returnval.resize(index_size);
976
977 for (unsigned int i=0; i != index_size; ++i) {
978 returnval.raw_at(i) = a.raw_at(i) * b;
979 returnval.raw_index(i) = a.raw_index(i);
980 }
981 return returnval;
982 }
983
984 template <template <class...> class SubType,
985 typename Data,
986 typename Indices,
987 class... SubTypeArgs,
988 typename T>
989 inline typename DividesType<SubType<SubTypeArgs...>, T>::supertype
990 operator/(const DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...> & a, const T & b)
991 {
992 const unsigned int index_size = a.size();
993
994 typename DividesType<SubType<SubTypeArgs...>,T>::supertype returnval;
995 returnval.resize(index_size);
996
997 for (unsigned int i=0; i != index_size; ++i) {
998 returnval.raw_at(i) = a.raw_at(i) / b;
999 returnval.raw_index(i) = a.raw_index(i);
1000 }
1001
1002 return returnval;
1003 }
1004
1005 #if __cplusplus >= 201103L
1006 template <template <class...> class SubType,
1007 typename Data,
1008 typename Indices,
1009 class... SubTypeArgs,
1010 typename T>
1011 inline typename MultipliesType<SubType<SubTypeArgs...>, T>::supertype
1012 operator*(DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...> && a, const T & b)
1013 {
1014 typename MultipliesType<SubType<SubTypeArgs...>,T>::supertype
1015 returnval = std::move(static_cast<SubType<SubTypeArgs...>&&>(a));
1016
1017 returnval *= b;
1018
1019 return returnval;
1020 }
1021
1022 template <template <class...> class SubType,
1023 typename Data,
1024 typename Indices,
1025 class... SubTypeArgs,
1026 typename T>
1027 inline typename DividesType<SubType<SubTypeArgs...>, T>::supertype
1028 operator/(DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...> && a, const T & b)
1029 {
1030 typename DividesType<SubType<SubTypeArgs...>,T>::supertype
1031 returnval = std::move(static_cast<SubType<SubTypeArgs...>&&>(a));
1032
1033 returnval /= b;
1034
1035 return returnval;
1036 }
1037 #endif
1038
1039
1040 #define DynamicSparseNumberBase_operator_binary(opname, functorname) \
1041 template <template <class...> class SubType, \
1042 typename Data, \
1043 typename Indices, \
1044 class... SubTypeArgs, \
1045 typename Data2, \
1046 typename Indices2, \
1047 class... SubTypeArgs2> \
1048 inline typename SubType<SubTypeArgs...>::template rebind< \
1049 bool, \
1050 typename CompareTypes<typename Indices::value_type, \
1051 typename Indices2::value_type>::supertype>::other \
1052 operator opname(const DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...> & a, \
1053 const DynamicSparseNumberBase<Data2, Indices2, SubType, SubTypeArgs2...> & b) \
1054 { \
1055 typedef typename Data::value_type T; \
1056 typedef typename Data2::value_type T2; \
1057 typedef typename Indices::value_type I; \
1058 typedef typename Indices2::value_type I2; \
1059 typedef typename SymmetricCompareTypes<T, T2>::supertype TS; \
1060 typedef typename CompareTypes<I, I2>::supertype IS; \
1061 typedef typename SubType<SubTypeArgs...>::template rebind< \
1062 bool, \
1063 typename CompareTypes<typename Indices::value_type, \
1064 typename Indices2::value_type>::supertype>::other RetType; \
1065 RetType returnval; \
1066 returnval.nude_indices() = a.nude_indices(); \
1067 returnval.nude_data().resize(a.nude_indices().size()); \
1068 returnval.sparsity_union(b.nude_indices()); \
1069 \
1070 auto index_a_it = a.nude_indices().begin(); \
1071 auto index_b_it = b.nude_indices().begin(); \
1072 auto index_out_it = returnval.nude_indices().begin(); \
1073 \
1074 auto data_a_it = a.nude_data().begin(); \
1075 auto data_b_it = b.nude_data().begin(); \
1076 auto data_out_it = returnval.nude_data().begin(); \
1077 \
1078 const IS maxIS = std::numeric_limits<IS>::max(); \
1079 \
1080 for (; index_out_it != returnval.nude_indices().end(); ++index_out_it, ++data_out_it) { \
1081 const IS index_a = (index_a_it == a.nude_indices().end()) ? maxIS : *index_a_it; \
1082 const IS index_b = (index_b_it == b.nude_indices().end()) ? maxIS : *index_b_it; \
1083 const IS index_out = *index_out_it; \
1084 const TS data_a = (index_a_it == a.nude_indices().end()) ? 0: *data_a_it; \
1085 const TS data_b = (index_b_it == b.nude_indices().end()) ? 0: *data_b_it; \
1086 TS & data_out = *data_out_it; \
1087 \
1088 if (index_a == index_out) { \
1089 if (index_b == index_out) { \
1090 data_out = data_a opname data_b; \
1091 index_b_it++; \
1092 data_b_it++; \
1093 } else { \
1094 data_out = data_a opname 0; \
1095 } \
1096 index_a_it++; \
1097 data_a_it++; \
1098 } else { \
1099 metaphysicl_assert_equal_to(index_b, index_out); \
1100 data_out = 0 opname data_b; \
1101 index_b_it++; \
1102 data_b_it++; \
1103 } \
1104 } \
1105 \
1106 return returnval; \
1107 } \
1108 template <template <class...> class SubType, \
1109 typename Data, \
1110 typename Indices, \
1111 class... SubTypeArgs, \
1112 typename T> \
1113 inline typename SubType<SubTypeArgs...>::template rebind<bool>::other operator opname( \
1114 const DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...> & a, const T & b) \
1115 { \
1116 typename SubType<SubTypeArgs...>::template rebind<bool>::other returnval; \
1117 \
1118 std::size_t index_size = a.size(); \
1119 returnval.resize(index_size); \
1120 returnval.nude_indices() = a.nude_indices(); \
1121 \
1122 for (unsigned int i=0; i != index_size; ++i) \
1123 returnval.raw_at(i) = (a.raw_at(i) opname b); \
1124 \
1125 return returnval; \
1126 } \
1127 template <template <class...> class SubType, \
1128 typename Data, \
1129 typename Indices, \
1130 class... SubTypeArgs, \
1131 typename T> \
1132 inline typename SubType<SubTypeArgs...>::template rebind<bool>::other operator opname( \
1133 const T & a, const DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...> & b) \
1134 { \
1135 typename SubType<SubTypeArgs...>::template rebind<bool>::other returnval; \
1136 \
1137 std::size_t index_size = a.size(); \
1138 returnval.nude_indices() = a.nude_indices(); \
1139 returnval.nude_data().resize(index_size); \
1140 \
1141 for (unsigned int i=0; i != index_size; ++i) \
1142 returnval.raw_at(i) = (a opname b.raw_at(i)); \
1143 \
1144 return returnval; \
1145 }
1146
1147 // NOTE: unary functions for which 0-op-0 is true are undefined compile-time
1148 // errors, because there's no efficient way to have them make sense in
1149 // the sparse context.
1150
1151 DynamicSparseNumberBase_operator_binary(<, less)
1152 // DynamicSparseNumberBase_operator_binary(<=)
1153 DynamicSparseNumberBase_operator_binary(>, greater)
1154 // DynamicSparseNumberBase_operator_binary(>=)
1155 // DynamicSparseNumberBase_operator_binary(==)
1156 DynamicSparseNumberBase_operator_binary(!=, not_equal_to)
1157
1158 // FIXME - make && an intersection rather than a union for efficiency
1159 DynamicSparseNumberBase_operator_binary(&&, logical_and)
1160 DynamicSparseNumberBase_operator_binary(||, logical_or)
1161
1162
1163 template <template <class...> class SubType, typename Data, typename Indices, class... SubTypeArgs>
1164 inline
1165 std::ostream&
1166 operator<< (std::ostream& output, const DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...>& a)
1167 {
1168 // Enclose the entire output in braces
1169 output << '{';
1170
1171 std::size_t index_size = a.size();
1172
1173 // Output the first value from a non-empty set
1174 // All values are given as ordered (index, value) pairs
1175 if (index_size)
1176 output << '(' << a.raw_index(0) << ',' <<
1177 a.raw_at(0) << ')';
1178
1179 // Output the comma-separated subsequent values from a non-singleton
1180 // set
1181 for (unsigned int i = 1; i < index_size; ++i)
1182 {
1183 output << ", (" << a.raw_index(i) << ',' << a.raw_data()[i] << ')';
1184 }
1185 output << '}';
1186 return output;
1187 }
1188
1189 } // namespace MetaPhysicL
1190
1191 namespace std {
1192
1193 using MetaPhysicL::CompareTypes;
1194 using MetaPhysicL::DynamicSparseNumberBase;
1195 using MetaPhysicL::SymmetricCompareTypes;
1196
1197 #define DynamicSparseNumberBase_std_unary(funcname) \
1198 template <template <class...> class SubType, \
1199 typename Data, typename Indices, class... SubTypeArgs> \
1200 inline \
1201 SubType<SubTypeArgs...> \
1202 funcname (const DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...> & a) \
1203 { \
1204 std::size_t index_size = a.size(); \
1205 SubType<SubTypeArgs...> returnval; \
1206 returnval.nude_indices() = a.nude_indices(); \
1207 returnval.nude_data().resize(index_size); \
1208 for (unsigned int i=0; i != index_size; ++i) \
1209 returnval.raw_at(i) = std::funcname(a.raw_at(i)); \
1210 \
1211 return returnval; \
1212 }
1213
1214
1215 #define DynamicSparseNumberBase_fl_unary(funcname) \
1216 DynamicSparseNumberBase_std_unary(funcname##f) \
1217 DynamicSparseNumberBase_std_unary(funcname##l)
1218
1219
1220 #define DynamicSparseNumberBase_stdfl_unary(funcname) \
1221 DynamicSparseNumberBase_std_unary(funcname) \
1222 DynamicSparseNumberBase_fl_unary(funcname)
1223
1224
1225 #define DynamicSparseNumberBase_std_binary_union(funcname) \
1226 template <template <class...> class SubType, \
1227 typename Data, \
1228 typename Indices, \
1229 class... SubTypeArgs, \
1230 typename Data2, \
1231 typename Indices2, \
1232 class... SubTypeArgs2> \
1233 inline typename SubType<SubTypeArgs...>::template rebind< \
1234 typename SymmetricCompareTypes<typename Data::value_type, \
1235 typename Data2::value_type>::supertype, \
1236 typename CompareTypes<typename Indices::value_type, \
1237 typename Indices2::value_type>::supertype>::other \
1238 funcname(const DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...> & a, \
1239 const DynamicSparseNumberBase<Data2, Indices2, SubType, SubTypeArgs2...> & b) \
1240 { \
1241 typedef typename Data::value_type T; \
1242 typedef typename Data2::value_type T2; \
1243 typedef typename Indices::value_type I; \
1244 typedef typename Indices2::value_type I2; \
1245 typedef typename SymmetricCompareTypes<T, T2>::supertype TS; \
1246 typedef typename CompareTypes<I, I2>::supertype IS; \
1247 typedef typename SubType<SubTypeArgs...>::template rebind< \
1248 typename SymmetricCompareTypes<typename Data::value_type, \
1249 typename Data2::value_type>::supertype, \
1250 typename CompareTypes<typename Indices::value_type, \
1251 typename Indices2::value_type>::supertype>::other RetType; \
1252 RetType returnval; \
1253 \
1254 std::size_t index_size = a.nude_indices.size(); \
1255 returnval.nude_indices = a.nude_indices; \
1256 returnval.nude_data.resize(index_size); \
1257 returnval.sparsity_union(b.nude_indices); \
1258 \
1259 auto index_a_it = a.nude_indices.begin(); \
1260 auto index_b_it = b.nude_indices.begin(); \
1261 auto index_out_it = returnval.nude_indices.begin(); \
1262 \
1263 auto data_a_it = a.nude_data.begin(); \
1264 auto data_b_it = b.nude_data.begin(); \
1265 auto data_out_it = returnval.nude_data.begin(); \
1266 \
1267 const IS maxIS = std::numeric_limits<IS>::max(); \
1268 \
1269 for (; index_out_it != returnval.nude_indices.end(); ++index_out_it, ++data_out_it) { \
1270 const IS index_a = (index_a_it == a.nude_indices.end()) ? maxIS : *index_a_it; \
1271 const IS index_b = (index_b_it == b.nude_indices.end()) ? maxIS : *index_b_it; \
1272 const IS index_out = *index_out_it; \
1273 const TS data_a = (index_a_it == a.nude_indices.end()) ? 0: *data_a_it; \
1274 const TS data_b = (index_b_it == b.nude_indices.end()) ? 0: *data_b_it; \
1275 TS & data_out = *data_out_it; \
1276 \
1277 if (index_a == index_out) { \
1278 if (index_b == index_out) { \
1279 data_out = std::funcname(data_a, data_b); \
1280 index_b_it++; \
1281 data_b_it++; \
1282 } else { \
1283 data_out = std::funcname(data_a, 0); \
1284 } \
1285 index_a_it++; \
1286 data_a_it++; \
1287 } else { \
1288 metaphysicl_assert_equal_to(index_b, index_out); \
1289 data_out = std::funcname(0, data_b); \
1290 index_b_it++; \
1291 data_b_it++; \
1292 } \
1293 } \
1294 \
1295 return returnval; \
1296 } \
1297 \
1298 template <template <class...> class SubType, \
1299 typename Data, \
1300 typename Indices, \
1301 class... SubTypeArgs, \
1302 typename T2> \
1303 inline typename SubType<SubTypeArgs...>::template rebind< \
1304 typename SymmetricCompareTypes<typename Data::value_type, T2>::supertype, \
1305 typename Indices::value_type>::other \
1306 funcname(const DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...> & a, \
1307 const T2 & b) \
1308 { \
1309 typedef typename Data::value_type T; \
1310 typedef typename SymmetricCompareTypes<T, T2>::supertype TS; \
1311 typedef \
1312 typename SubType<SubTypeArgs...>::template rebind<TS, typename Indices::value_type>::other \
1313 RetType; \
1314 RetType returnval; \
1315 \
1316 std::size_t index_size = a.size(); \
1317 returnval.resize(index_size); \
1318 returnval.nude_indices = a.nude_indices; \
1319 \
1320 for (unsigned int i=0; i != index_size; ++i) \
1321 returnval.raw_at(i) = std::funcname(a.raw_at(i), b); \
1322 \
1323 return returnval; \
1324 } \
1325 \
1326 template <template <class...> class SubType, \
1327 typename Data, \
1328 typename Indices, \
1329 class... SubTypeArgs, \
1330 typename T> \
1331 inline typename SubType<SubTypeArgs...>::template rebind< \
1332 typename SymmetricCompareTypes<T, typename Data::value_type>::supertype, \
1333 typename Indices::value_type>::other \
1334 funcname(const T & a, const DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...> & b) \
1335 { \
1336 typedef typename Data::value_type T2; \
1337 typedef typename SymmetricCompareTypes<T, T2>::supertype TS; \
1338 typedef \
1339 typename SubType<SubTypeArgs...>::template rebind<TS, typename Indices::value_type>::other \
1340 RetType; \
1341 RetType returnval; \
1342 \
1343 std::size_t index_size = a.size(); \
1344 returnval.resize(index_size); \
1345 returnval.nude_indices = b.nude_indices; \
1346 \
1347 for (unsigned int i=0; i != index_size; ++i) \
1348 returnval.raw_at(i) = std::funcname(a, b.raw_at(i)); \
1349 \
1350 return returnval; \
1351 }
1352
1353
1354 #define DynamicSparseNumberBase_fl_binary_union(funcname) \
1355 DynamicSparseNumberBase_std_binary_union(funcname##f) \
1356 DynamicSparseNumberBase_std_binary_union(funcname##l)
1357
1358
1359 #define DynamicSparseNumberBase_stdfl_binary_union(funcname) \
1360 DynamicSparseNumberBase_std_binary_union(funcname) \
1361 DynamicSparseNumberBase_fl_binary_union(funcname)
1362
1363
1364 // Pow needs its own specialization, both to avoid being confused by
1365 // pow<T1,T2> and because pow(x,0) isn't 0.
1366 template <template <class...> class SubType,
1367 typename Data,
1368 typename Indices,
1369 class... SubTypeArgs,
1370 typename T2>
1371 inline typename SubType<SubTypeArgs...>::template rebind<
1372 typename SymmetricCompareTypes<typename Data::value_type, T2>::supertype,
1373 typename Indices::value_type>::other
pow(const DynamicSparseNumberBase<Data,Indices,SubType,SubTypeArgs...> & a,const T2 & b)1374 pow(const DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...> & a, const T2 & b)
1375 {
1376 typedef typename Data::value_type T;
1377 typedef typename SymmetricCompareTypes<T, T2>::supertype TS;
1378 typedef typename SubType<SubTypeArgs...>::template rebind<TS, typename Indices::value_type>::other
1379 RetType;
1380 RetType returnval;
1381
1382 std::size_t index_size = a.size();
1383 returnval.nude_indices() = a.nude_indices();
1384 returnval.nude_data().resize(index_size);
1385
1386 for (unsigned int i=0; i != index_size; ++i)
1387 returnval.raw_at(i) = std::pow(a.raw_at(i), b);
1388
1389 return returnval;
1390 }
1391
1392
1393 // NOTE: unary functions for which f(0) != 0 are undefined compile-time
1394 // errors, because there's no efficient way to have them make sense in
1395 // the sparse context.
1396
1397 // DynamicSparseNumberBase_std_binary(pow) // separate definition
1398 // DynamicSparseNumberBase_std_unary(exp)
1399 // DynamicSparseNumberBase_std_unary(log)
1400 // DynamicSparseNumberBase_std_unary(log10)
1401 DynamicSparseNumberBase_std_unary(sin)
1402 // DynamicSparseNumberBase_std_unary(cos)
1403 DynamicSparseNumberBase_std_unary(tan)
1404 DynamicSparseNumberBase_std_unary(asin)
1405 // DynamicSparseNumberBase_std_unary(acos)
1406 DynamicSparseNumberBase_std_unary(atan)
1407 DynamicSparseNumberBase_std_binary_union(atan2)
1408 DynamicSparseNumberBase_std_unary(sinh)
1409 // DynamicSparseNumberBase_std_unary(cosh)
1410 DynamicSparseNumberBase_std_unary(tanh)
1411 DynamicSparseNumberBase_std_unary(sqrt)
1412 DynamicSparseNumberBase_std_unary(abs)
1413 DynamicSparseNumberBase_std_unary(fabs)
1414 DynamicSparseNumberBase_std_binary_union(max)
1415 DynamicSparseNumberBase_std_binary_union(min)
1416 DynamicSparseNumberBase_std_unary(ceil)
1417 DynamicSparseNumberBase_std_unary(floor)
1418 DynamicSparseNumberBase_std_binary_union(fmod) // TODO: optimize this
1419
1420 #if __cplusplus >= 201103L
1421 DynamicSparseNumberBase_std_unary(llabs)
1422 DynamicSparseNumberBase_std_unary(imaxabs)
1423 DynamicSparseNumberBase_fl_unary(fabs)
1424 DynamicSparseNumberBase_stdfl_unary(expm1)
1425 DynamicSparseNumberBase_fl_unary(sqrt)
1426 DynamicSparseNumberBase_stdfl_unary(cbrt)
1427 DynamicSparseNumberBase_fl_unary(sin)
1428 DynamicSparseNumberBase_fl_unary(tan)
1429 DynamicSparseNumberBase_fl_unary(asin)
1430 DynamicSparseNumberBase_fl_unary(atan)
1431 DynamicSparseNumberBase_stdfl_unary(asinh)
1432 DynamicSparseNumberBase_stdfl_unary(atanh)
1433 DynamicSparseNumberBase_stdfl_unary(erf)
1434 DynamicSparseNumberBase_fl_unary(ceil)
1435 DynamicSparseNumberBase_fl_unary(floor)
1436 DynamicSparseNumberBase_stdfl_unary(trunc)
1437 DynamicSparseNumberBase_stdfl_unary(round)
1438 DynamicSparseNumberBase_stdfl_unary(nearbyint)
1439 DynamicSparseNumberBase_stdfl_unary(rint)
1440
1441 DynamicSparseNumberBase_fl_binary_union(fmod)
1442 DynamicSparseNumberBase_stdfl_binary_union(remainder) // TODO: optimize this
1443 DynamicSparseNumberBase_stdfl_binary_union(fmax)
1444 DynamicSparseNumberBase_stdfl_binary_union(fmin)
1445 DynamicSparseNumberBase_stdfl_binary_union(fdim)
1446 DynamicSparseNumberBase_stdfl_binary_union(hypot)
1447 DynamicSparseNumberBase_fl_binary_union(atan2)
1448 #endif // __cplusplus >= 201103L
1449
1450 #define DynamicSparseNumberBase_std_unary_complex(funcname) \
1451 template <template <class...> class SubType, \
1452 typename Data, \
1453 typename Indices, \
1454 class... SubTypeArgs> \
1455 inline auto funcname(const DynamicSparseNumberBase<Data, Indices, SubType, SubTypeArgs...> & in) \
1456 ->typename SubType<SubTypeArgs...>::template rebind<decltype(std::funcname( \
1457 typename Data::value_type())), \
1458 typename Indices::value_type>::other \
1459 { \
1460 typedef typename SubType<SubTypeArgs...>::template rebind< \
1461 decltype(std::funcname(typename Data::value_type())), \
1462 typename Indices::value_type>::other RetType; \
1463 RetType returnval; \
1464 auto size = in.size(); \
1465 returnval.nude_indices() = in.nude_indices(); \
1466 returnval.nude_data().resize(size); \
1467 \
1468 for (decltype(size) i = 0; i < size; ++i) \
1469 returnval.raw_at(i) = std::funcname(in.raw_at(i)); \
1470 return returnval; \
1471 }
1472
1473 DynamicSparseNumberBase_std_unary_complex(real)
1474 DynamicSparseNumberBase_std_unary_complex(imag)
1475 DynamicSparseNumberBase_std_unary_complex(norm)
1476 } // namespace std
1477
1478
1479 #endif // METAPHYSICL_DYNAMICSPARSENUMBERARRAY_H
1480