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