32 #include <sys/types.h>
33 #include "juice/variant.hpp"
34 #include "allocator_factory.hpp"
38 #include "globals.hpp"
39 #include "base_types.hpp"
47 using namespace Juice;
48 using namespace std::string_literals;
59 constexpr seq_n_t seq_n { };
64 typedef uint64_t idx_type;
72 template <
typename V1,
typename V2>
73 inline bool checksize(
const V1& v1,
const V2& v2) {
return v1.size() == v2.size(); }
74 template <
typename V1,
typename V2,
typename... U>
75 inline bool checksize(
const V1& v1,
const V2& v2,
const U&... u) {
76 return checksize<V1,V2>(v1, v2) &&
checksize<V1, U...>(v1, u...);
85 template <
typename V1,
typename V2>
86 inline bool checkdims(
const V1& v1,
const V2& v2) {
87 return v1.ncols() == v2.ncols() && v1.size() == v2.size(); }
88 template <
typename V1,
typename V2,
typename... U>
89 inline bool checkdims(
const V1& v1,
const V2& v2,
const U&... u) {
90 return checkdims<V1,V2>(v1, v2) &&
checkdims<V1, U...>(v1, u...);
99 void buildNames(vector<unique_ptr<Dname>>& names,
100 const Vector<idx_type> dim,
101 const AllocFactory& allocf,
102 const vector<Vector<zstring>> names_p={Vector<zstring>()});
108 template<
typename T,
typename O=std::less<T>>
111 typedef T value_type;
112 typedef O comparator;
120 std::unique_ptr<AllocFactory>&& allocf_p=std::make_unique<MemAllocFactory>())
121 : allocf(std::move(allocf_p))
123 if (by <= getInitValue<U>()) {
124 throw std::out_of_range(
"'by' parameter must be >= 0");
126 auto n =
static_cast<idx_type
>((t1 < t2 ? t2 - t1 : t1 - t2) / by) + 1;
128 v.emplace_back(make_unique<
Vector<T,O>>(noinit_tag, n, allocf->get(0)));
132 for (idx_type i=0; i<n; ++i) {
133 setv_nocheck(*v[0], i,
val);
137 for (idx_type i=0; i<n; ++i) {
138 setv_nocheck(*v[0], i,
val);
142 v[0]->setOrdered(n <= 1 || O()(t1, t2));
149 std::unique_ptr<AllocFactory>&& allocf_p=std::make_unique<MemAllocFactory>())
150 : allocf(std::move(allocf_p))
153 v.emplace_back(make_unique<
Vector<T,O>>(rsv, n, allocf->get(0)));
155 for (idx_type i=1; i<n; ++i) {
156 v[0]->push_back((*v[0])[i-1] + by);
163 template<
typename INIT_TYPE_TAG>
167 std::unique_ptr<AllocFactory>&& allocf_p=std::make_unique<MemAllocFactory>())
168 : dim(dim_p), allocf(std::move(allocf_p))
175 auto ncols = accumulate(dim.begin()+1, dim.end(), 1.0, std::multiplies<idx_type>());
178 for (idx_type n=0; n<ncols; ++n) {
179 v[n] = make_unique<Vector<T,O>>(init, dim[0], allocf->get(n));
188 Array(std::unique_ptr<AllocFactory>&& allocf_p)
189 : allocf(std::move(allocf_p))
194 auto ncols = dim.size() ?
195 accumulate(dim.begin()+1, dim.end(), 1.0, std::multiplies<idx_type>()) : 0;
196 for (idx_type j=0; j<ncols; ++j) {
197 v.emplace_back(make_unique<
Vector<T,O>>(allocf->get(j)));
200 for (idx_type j=0; j<dim.size(); ++j) {
202 (make_unique<Dname>(dim[j],
Vector<zstring>(allocf->get(
"names" + std::to_string(j)))));
210 std::unique_ptr<AllocFactory>&& allocf_p=std::make_unique<MemAllocFactory>())
211 : allocf(std::move(allocf_p))
214 auto ncols = dim.size() ?
215 accumulate(dim.begin()+1, dim.end(), 1.0, std::multiplies<idx_type>()) : 0;
217 if (v_p.
size() == 0) {
218 for (idx_type n=0; n<ncols; ++n) {
219 v.emplace_back(make_unique<
Vector<T,O>>(rsv, dim[0], allocf->get(n)));
222 else if (v_p.
size() == 1) {
223 for (idx_type n=0; n<ncols; ++n) {
224 v.emplace_back(make_unique<Vector<T,O>>(dim[0], v_p[0], allocf->get(n)));
227 if (v_p.getdim(0) == dim[0] && ncols == v_p.v.size()) {
229 for (idx_type n=0; n<ncols; ++n) {
230 v.emplace_back(make_unique<Vector<T,O>>(*v_p.v[n], allocf->get(n)));
234 if (v_p.
size() != ncols * dim[0]) {
235 throw range_error(
"data does not fit array dimensions");
239 for (idx_type n=0; n<ncols; ++n) {
240 v.emplace_back(make_unique<Vector<T,O>>(rsv, dim[0], allocf->get(n)));
241 for (idx_type i=0; i<dim[0]; ++i) {
242 v.back()->push_back(v_p[idx++]);
257 std::unique_ptr<AllocFactory>&& allocf_p=std::make_unique<MemAllocFactory>())
258 : allocf(std::move(allocf_p))
264 auto ncols = dim.size() ?
265 accumulate(dim.begin()+1, dim.end(), 1.0, std::multiplies<idx_type>()) : 0;
267 if (v_p.size() == 0) {
275 for (idx_type n=0; n<ncols; ++n) {
276 v.emplace_back(make_unique<
Vector<T,O>>(dim[0], getInitValue<T>(), allocf->get(n)));
279 else if (v_p.size() == 1) {
280 for (idx_type n=0; n<ncols; ++n) {
281 v.emplace_back(make_unique<
Vector<T,O>>(dim[0], v_p[0], allocf->get(n)));
284 if (v_p.size() != ncols * dim[0]) {
285 throw range_error(
"data does not fit array dimensions");
288 for (idx_type n=0; n<ncols; ++n) {
289 v.emplace_back(make_unique<
Vector<T,O>>(v_p.begin() + offset,
290 v_p.begin() + offset + dim[0],
302 const vector<unique_ptr<Dname>>& names_p,
303 std::unique_ptr<AllocFactory>&& allocf_p=std::make_unique<MemAllocFactory>())
304 : dim(dim_p), allocf(std::move(allocf_p))
307 if (dim_p.size() == 1) {
308 cout <<
"nearly copying array " << dim_p[0] << endl;
311 cout <<
"nearly copying array " << dim_p[0] <<
"x" << dim_p[1] << endl;
314 for (
auto& e : v_p) {
317 for (
auto& e : names_p) {
318 names.emplace_back(make_unique<Dname>(*e));
324 std::unique_ptr<AllocFactory>&& allocf_p=std::make_unique<MemAllocFactory>())
325 : allocf(std::move(allocf_p)) {
327 if (u.dim.size() == 1) {
328 cout <<
"copying array " << u.dim[0] << endl;
331 cout <<
"copying array " << u.dim[0] <<
"x" << u.dim[1] << endl;
334 dim = Vector<idx_type>(u.dim, allocf->get(
"dim"));
336 v.reserve(u.v.size());
337 for (idx_type i=0; i<u.v.size(); ++i) {
338 v.emplace_back(make_unique<Vector<T,O>>(Vector<T,O>(*u.v[i]), allocf->get(i)));
340 for (idx_type i=0; i<u.
names.size(); ++i) {
342 (make_unique<Dname>(dim[i],
343 Vector<zstring>(u.
names[i]->names,
344 allocf->get(
"names" + std::to_string(i)))));
349 template<
typename U,
typename OU=std::less<U>>
351 std::unique_ptr<AllocFactory>&& allocf_p=std::make_unique<MemAllocFactory>())
352 : dim(u.dim), allocf(std::move(allocf_p))
354 v.reserve(u.v.size());
355 for (idx_type n=0; n<u.v.size(); ++n) {
356 v.emplace_back(make_unique<
Vector<T,O>>(rsv, dim[0]));
357 for (idx_type r=0; r<dim[0]; ++r) {
358 v[n]->push_back(convert<T,U>((*u.v[n])[r]));
361 for (
auto& e : u.
names) {
362 names.emplace_back(make_unique<Dname>(
Dname(*e)));
368 if (u.dim.size() == 1) {
369 cout <<
"swapping array on universal reference " << u.dim[0] << endl;
372 cout <<
"swapping array on universal reference " << u.dim[0] <<
"x" << u.dim[1] << endl;
393 template<
typename U,
class G>
394 Array(
const Array<U>& u, G g,
bool abba,
395 std::unique_ptr<AllocFactory>&& allocf_p=std::make_unique<MemAllocFactory>())
398 v.reserve(u.v.size());
399 for (idx_type n=0; n<u.v.size(); ++n) {
400 v.emplace_back(make_unique<Vector<T,O>>());
403 for (
auto& e : u.names) {
404 names.emplace_back(make_unique<Dname>(Dname(*e)));
408 Array(Vector<T,O>&& vv) : dim({vv.size()}) {
409 v.emplace_back(make_unique<Vector<T,O>>(vv));
410 names.emplace_back(make_unique<Dname>(vv.size()));
416 Array& operator=(Array u) {
418 if (u.dim.size() == 1) {
419 cout <<
"array assignment " << u.dim[0] << endl;
422 cout <<
"array assignment " << u.dim[0] <<
"x" << u.dim[1] << endl;
428 Array& swap(Array& u) {
430 std::swap(dim, u.dim);
431 std::swap(names, u.names);
432 std::swap(allocf, u.allocf);
440 for (idx_type j=0; j<u.
names.size(); ++j) {
441 if (*names[j] != *u.
names[j]) {
445 for (idx_type j=0; j<u.v.size(); ++j) {
446 if (*v[j] != *u.v[j]) {
458 inline T& operator[](idx_type i) {
460 throw range_error(
"subscript out of bounds");
462 idx_type col = i / dim[0];
463 idx_type off = i % dim[0];
464 if (col >= v.size() || off >= dim[0]) {
465 throw range_error(
"subscript out of bounds");
467 return (*v[col].get())[off];
471 inline const T& operator[](idx_type i)
const {
473 throw range_error(
"subscript out of bounds");
475 idx_type col = i / dim[0];
476 idx_type off = i % dim[0];
478 if (col >= v.size() || off >= dim[0]) {
479 throw range_error(
"subscript out of bounds");
481 return (*v[col])[off];
491 return dim.getBufferSize() + v.size() * v[0]->getBufferSize();
494 size_t to_buffer(
char* buf)
const {
498 offset += dim.to_buffer(buf);
499 for (
auto& colptr : v) {
500 offset += colptr->to_buffer(buf + offset);
514 template<
typename INDEX>
521 for (idx_type k=0; k<v.size(); ++k) {
522 i.subset(*r.v[0], *v[k], ii, iv, pos);
526 arr::setv(r.dim, 0, r.v[0]->size());
527 r.names[0]->resize(r.v[0]->size());
531 template<
typename INDEX>
532 Array operator()(
const vector<INDEX>& i,
bool drop=
true, idx_type dropfirst=0)
const {
533 if (i.size() == 1 && dim.size() > 1) {
534 return (*
this)(i[0]);
536 if (i.size() != dim.size()) {
537 throw std::range_error(
"incorrect number of dimensions");
541 Vector<idx_type> rdim(i.size());
542 auto transfop = [](
const INDEX& i) {
return i.size(); };
543 std::transform(i.begin(), i.end(), rdim.begin(), transfop);
544 auto rdimUndropped = rdim;
545 if (drop && dropfirst<rdim.size()) {
546 rdim.erase(std::remove_if(rdim.begin()+dropfirst,
548 [](idx_type i) { return i == 1; }),
555 idx_type rncols = rdim.size() == 1 ? 1 :
556 accumulate(rdim.begin()+1, rdim.end(), 1.0, std::multiplies<idx_type>());
557 auto pi = vector<idx_type>(dim.size(), 0);
558 auto val = vector<idx_type>(dim.size(), 0);
559 auto rv = vector<unique_ptr<Vector<T,O>>>();
561 for (idx_type j=0; j<rncols; ++j) {
562 rv.emplace_back(make_unique<Vector<T,O>>());
570 if (drop && dropfirst==0 && rdimUndropped[0] == 1) {
573 auto r = i[0].getfirst(uidx, pidx);
576 throw std::range_error(
"failed getfirst on dim[0] = 1");
578 if (uidx >= dim[0]) {
579 throw range_error(
"subscript out of bounds");
581 bool res = INDEX::getfirstcol(col,
val, pi, i, dim);
584 if (col >= v.size()) {
585 throw range_error(
"subscript out of bounds");
587 rv[rcol]->push_back((*v[col])[uidx]);
588 if (rv[rcol]->size() == rdim[0]) {
591 res = INDEX::getnextcol(col,
val, pi, i, dim);
600 bool res = INDEX::getfirstcol(col,
val, pi, i, dim);
603 i[0].subset(*rv[rcol], *v[col]);
604 res = INDEX::getnextcol(col,
val, pi, i, dim);
610 if (rv.size() && rv[0]->size() != rdim[0]) {
611 if (drop && dropfirst==0 && rv[0]->size() == 1 && rv.size()!=1) {
612 throw range_error(
"resize first dim to 1 not implemented");
615 arr::setv(rdim, 0, rv[0]->size());
621 auto rnames = vector<unique_ptr<Dname>>();
622 idx_type rnameIdx = 0;
623 for (idx_type j=0; j<rdimUndropped.size(); ++j) {
624 bool scalarResult = rdim.size()==1 && rdim[0]==1;
627 bool cond1 = j==0 && drop && dropfirst==0 && rdimUndropped[0]==1 && !scalarResult;
629 bool cond2 = j>0 && drop && dropfirst <= j && rdimUndropped[j]==1;
631 if (!cond1 && !cond2) {
632 rnames.emplace_back(make_unique<Dname>(0));
633 if (names[j]->names.size() > 0) {
634 i[j].selectNames(*rnames[rnameIdx], *names[j]);
637 *rnames[rnameIdx] = Dname(rdim[rnameIdx]);
643 return Array<T>(rdim, rv, rnames);
651 template<
typename INDEX,
typename U>
653 if (i.size() != dim.size()) {
654 throw std::range_error(
"incorrect number of dimensions");
660 idx_type nelts = i[0].trueSize();
661 for (idx_type d = 1; d < i.size(); ++d) {
662 nelts *= i[d].trueSize();
664 if (nelts != u.
size()) {
665 throw range_error(
"number of items to replace is not equal to the replacement length");
669 auto pi = vector<idx_type>(dim.size(), 0);
670 auto val = vector<idx_type>(dim.size(), 0);
672 bool res = INDEX::getfirstcol(col,
val, pi, i, dim);
675 if (col >= v.size()) {
676 throw range_error(
"subscript out of bounds");
678 i[0].subassign(*v[col], u, uj);
679 res = INDEX::getnextcol(col,
val, pi, i, dim);
685 template<
typename INDEX,
typename U>
687 if (i.size() != dim.size()) {
688 throw std::range_error(
"incorrect number of dimensions");
692 auto pi = vector<idx_type>(dim.size(), 0);
693 auto val = vector<idx_type>(dim.size(), 0);
695 bool res = INDEX::getfirstcol(col,
val, pi, i, dim);
703 if (col >= v.size()) {
704 throw range_error(
"subscript out of bounds");
706 i[0].subassignScalar(*v[col], u);
707 res = INDEX::getnextcol(col,
val, pi, i, dim);
713 T operator[](
const vector<idx_type>& i)
const {
714 if (i.size() != dim.size()) {
715 throw range_error(
"index dimension mismatch");
717 if (i[0] >= dim[0]) {
718 throw range_error(
"subscript out of bounds");
722 for (idx_type k=1; k<dim.size(); ++k) {
723 if (i[k] >= dim[k]) {
724 throw range_error(
"subscript out of bounds");
729 return (*v[col])[i[0]];
735 if (from + n > dim[0]) {
736 throw range_error(
"range out of bounds");
739 arr::setv(aDim, 0, n);
740 Array a(arr::rsv, aDim);
741 for (idx_type i=0; i<ncols(); ++i) {
742 for (idx_type j=from; j<from+n; ++j) {
743 a.v[i]->push_back((*v[i])[j]);
748 if (hasNames(0) || addrownums) {
749 for (idx_type j=from; j<from+n; ++j) {
750 (*a.
names[0]).assign(j-from, hasNames(0) ? (*names[0])[j] :
751 "[" +std::to_string(j+1)+std::string(dim.size()-1,
',')+
"]");
755 for (idx_type j=1; j<dim.size(); ++j) {
756 *a.
names[j] = *names[j];
762 inline bool hasNames()
const {
763 for (arr::idx_type d=0; d<dim.size(); ++d) {
771 inline bool hasNames(idx_type d)
const {
772 if (d >= names.size()) {
773 throw out_of_range(
"name index out of bound");
775 return names[d]->hasNames();
778 inline const Dname& getNames(idx_type d)
const {
779 if (d >= names.size()) {
780 throw out_of_range(
"name index out of bound");
785 inline const Vector<zstring>& getNamesVector(idx_type d)
const {
786 if (d >= names.size()) {
787 throw out_of_range(
"name index out of bound");
789 return names[d]->names;
792 inline bool isVector()
const {
796 inline bool isScalar()
const {
797 return dim.size() == 1 && dim[0] == 1;
800 inline bool isOrdered()
const {
801 return std::all_of(v.begin(), v.end(), [](
const auto& e){ return e->isOrdered(); });
804 inline bool isOrdered(idx_type i)
const {
805 return v[i]->isOrdered();
808 inline const AllocFactory& getAllocFactory()
const {
return *allocf.get(); }
810 Array& addprefix(
const string& prefix, idx_type d) {
811 if (prefix.length() > 0) {
812 if (d < dim.size()) {
813 names[d]->addprefix(prefix);
815 else if (d >= dim.size()) {
818 for (idx_type j=dim.size(); j<d+1; ++j) {
819 names.emplace_back(make_unique<Dname>(1));
822 names[d]->addprefix(prefix);
825 throw range_error(
"addprefix: dimension out of range");
833 inline idx_type
size()
const {
return v.size() * nrows(); }
834 inline idx_type ncols()
const {
return v.size(); }
835 inline idx_type nrows()
const {
return dim.size() ? dim[0] : 0; }
838 inline const Vector<T,O>& getcol(idx_type i)
const {
840 throw std::out_of_range(
"getcol: column out of range");
844 inline Vector<T,O>& getcol(idx_type i) {
846 throw std::out_of_range(
"getcol: column out of range");
848 return *(v[i].get());
853 if (d >= names.size()) {
854 throw std::out_of_range(
"getnames: dimension out of range");
859 inline const idx_type getdim(idx_type d)
const {
860 if (d >= dim.size()) {
861 throw std::out_of_range(
"getdim: dimension out of range");
866 inline fsys::path getAllocfDirname()
const {
return allocf->getDirname(); }
867 inline bool isPersistent()
const {
return allocf->isPersistent(); }
869 void msync(
bool async)
const {
870 dim.getAllocator()->msync(async);
871 for (
auto& col : v) {
872 col->getAllocator()->msync(async);
874 for (
auto& nm : names) {
875 nm->names.getAllocator()->msync(async);
885 if (!v.size() || !u.size()) {
888 idx_type up = min(v.size(), u.size());
889 for (idx_type j=0; j<up; ++j) {
890 if (j == i)
continue;
896 for (idx_type j=up; j<v.size(); ++j) {
897 if (j == i)
continue;
898 if (v[j] != 1)
return false;
900 for (idx_type j=up; j<u.size(); ++j) {
901 if (j == i)
continue;
902 if (u[j] != 1)
return false;
911 if (dim.size() > 1 || u.dim.size() > 1) {
912 throw range_error(
"concat can only handle dim==0 and vectors");
914 for (
auto e: *u.v[0]) {
915 v[0]->push_back(convert<T,U>(e));
917 auto newnames = *u.
names[0];
918 if (prefix.length()) {
919 newnames.addprefix(prefix);
921 names[0]->addafter(newnames);
922 setv(dim, 0, dim[0] + u.dim[0]);
931 if (dim.size() == 0) {
933 names.push_back(make_unique<Dname>(0));
935 else if (dim.size() > 1) {
936 throw range_error(
"concat can only handle dim==0 and vectors");
942 v[0]->push_back(convert<T,U>(u));
943 names[0]->addafter(name);
944 arr::setv(dim, 0, dim[0] + 1);
958 if (
reinterpret_cast<const Array<U>*
>(
this) == &u) {
960 throw range_error(
"cannot bind to self.");
968 if (dim.size() == 1) {
969 *
this = transpose(*
this);
970 return abind<U>(u.dim.size() == 1 ? transpose(u) : u, d, prefix);
972 else if (u.dim.size() == 1) {
973 return abind<U>(transpose(u), d, prefix);
977 throw range_error(
"incorrect dimensions for abind");
981 if (dim.size() == 0) {
982 for (idx_type j=0; j<u.dim.size(); ++j) {
983 dim.push_back(j == d ? 0 : u.dim[j]);
985 make_unique<Dname>(j == d ? 0 : u.dim[j],
987 allocf->get(
"names" + std::to_string(j)))));
991 if (d >= dim.size()) {
996 for (idx_type j=dim.size(); j<d+1; ++j) {
998 make_unique<Dname>(v.size()==0 && j==d ? 0 : 1,
1000 allocf->get(
"names" + std::to_string(j)))));
1001 dim.push_back(v.size()==0 && j==d ? 0 : 1);
1006 for (idx_type j=0; j<u.v.size(); ++j) {
1007 if (j >= v.size()) {
1009 v.emplace_back(make_unique<
Vector<T,O>>(rsv, u.v[j]->size(),
1010 allocf->get(std::to_string(j))));
1012 for (
auto e: *u.v[j]) {
1013 v[j]->push_back(convert<T,U>(e));
1018 auto origSize = v.size();
1019 v.reserve(origSize + u.v.size());
1020 for (idx_type j=0; j<u.v.size(); ++j) {
1022 v.emplace_back(make_unique<
Vector<T,O>>(rsv, dim[0],
1023 allocf->get(std::to_string(origSize+j))));
1025 idx_type ucols = d < u.dim.size() ?
1026 accumulate(u.dim.begin()+1, u.dim.begin()+d+1, 1, multiplies<idx_type>()) :
1027 accumulate(u.dim.begin()+1, u.dim.end(), 1, multiplies<idx_type>());
1028 idx_type cols = d < dim.size() ?
1029 accumulate(dim.begin()+1, dim.begin()+d+1, 1, multiplies<idx_type>()) :
1030 accumulate(dim.begin()+1, dim.end(), 1, multiplies<idx_type>());
1032 idx_type n = d < dim.size() ?
1033 accumulate(dim.begin()+d+1, dim.end(), 1, multiplies<idx_type>()) : 1;
1034 idx_type destoff = v.size() - 1;
1035 idx_type srcoff = origSize - 1;
1036 idx_type uoff = u.v.size() - 1;
1037 for (idx_type j=n; j>0; --j) {
1039 bool needSwap =
true;
1040 for (idx_type k=0; k < ucols; ++k) {
1041 for (idx_type l=0; l<u.v[uoff]->size(); ++l) {
1042 v[destoff]->push_back(convert<T,U>((*u.v[uoff])[l]));
1053 for (idx_type k=0; k < cols; ++k) {
1054 std::swap(v[srcoff--], v[destoff--]);
1060 auto newnames = d < u.dim.size() ? *u.
names[d] :
Dname(1);
1061 newnames.addprefix(prefix);
1062 names[d]->addafter(newnames);
1064 for (idx_type i=0; i<names.size(); ++i) {
1066 if (!hasNames(i) && i < u.
names.size() && u.hasNames(i)) {
1067 *names[i] = *u.
names[i];
1070 setv(dim, d, dim[d] + (d < u.dim.size() ? u.dim[d] : 1));
1074 template<
typename U>
1076 return abind<U>(u, 0);
1079 template<
typename U>
1080 Array& cbind(
const Array<U>& u) {
1081 return abind<U>(u, 1);
1089 if (dim.size() == 0) {
1092 throw out_of_range(
"append on null array not implemented");
1095 throw out_of_range(
"incorrect dimensions for append");
1100 for (
size_t i=0; i<v.size(); ++i) {
1101 offset += v[i]->append(buf + offset, buflen - offset);
1105 for (
size_t i=0; i<v.size(); ++i) {
1106 v[i]->resize(dim[0]);
1114 names[0]->addafter(
Dname(adim[0]));
1115 setv(dim, 0, dim[0] + adim[0]);
1121 auto data =
Vector<T,O>(
const_cast<char*
>(buf), buflen);
1123 if (v.size() == 0) {
1126 throw out_of_range(
"appendVector on null array not implemented");
1128 if (data.size() % v.size()) {
1129 throw out_of_range(
"appendVector: incorrect vector size");
1131 idx_type nrows = data.size() / v.size();
1132 idx_type i = 0, j=0;
1133 for (
auto e : data) {
1135 if (++j == nrows) { j = 0; ++i; }
1138 names[0]->addafter(
Dname(nrows));
1139 setv(dim, 0, dim[0] + nrows);
1144 Array& resize(idx_type d, idx_type sz, idx_type from=0) {
1146 throw logic_error(
"resize only implemented for dim 0");
1148 if (dim.size() == 0) {
1150 names.push_back(make_unique<Dname>(0));
1152 if (v.size() == 0) {
1153 v.push_back(make_unique<Vector<T,O>>(dim[0]));
1156 for (idx_type j=0; j<v.size(); ++j) {
1157 v[j]->resize(sz, from);
1160 names[0]->resize(sz, from);
1169 for (idx_type n=0; n<v.size(); ++n) {
1170 for (idx_type i=0; i<v[n]->size(); ++i) {
1171 setv_checkbefore(*v[n], i, f((*v[n])[i]));
1181 template<
typename F,
typename ...U>
1183 if (!
checksize(*
this, u...))
throw std::out_of_range(
"size mismatch");
1184 for (idx_type n=0; n<v.size(); ++n) {
1185 v[n]->template
apply<F,
typename U::vector_type...>(u.getcol(n)...);
1190 template<
class F,
typename U>
1191 Array& apply_scalar_post(U u) {
1192 for (idx_type n=0; n<v.size(); ++n) {
1193 v[n]->template apply_scalar_post<F, U>(u);
1198 template<
typename F,
typename U>
1199 Array&
apply(
const U& u) {
1200 if (u.size() == 1) {
1201 return apply_scalar_post<F, typename U::value_type>(u[0]);
1203 for (idx_type n=0; n<v.size(); ++n) {
1204 v[n]->template apply<F, typename U::vector_type>(u.getcol(n));
1209 template<
class F,
typename U,
typename A>
1210 Array& apply_attrib(
const Array<U>& u,
const A& a) {
1211 if (u.size() == 1) {
1212 return apply_attrib_scalar_post<F,U>(u[0], a);
1215 if (!
checkdims(dim, u.dim, std::max(dim.size(), u.size()) + 1)) {
1216 throw(std::out_of_range(
"in apply, array dimension mismatch"));
1218 for (idx_type n=0; n<v.size(); ++n) {
1219 for (idx_type i=0; i<v[n]->size(); ++i) {
1220 setv_checkbefore(*v[n], i, F()((*v[n])[i], (*u.v[n])[i], a));
1226 template<
class F,
typename U,
typename A>
1227 Array& apply_attrib_scalar_post(U u,
const A& a) {
1228 for (idx_type n=0; n<v.size(); ++n) {
1229 for (idx_type i=0; i<v[n]->size(); ++i) {
1230 setv_checkbefore(*v[n], i, F()((*v[n])[i], u, a));
1237 template <
typename AO=O>
1239 std::for_each(v.begin(), v.end(), [](
const auto& e){ e->template sort<AO>(); });
1243 template <
typename AO=O>
1244 Array& sort(idx_type col) {
1245 if (col >= v.size()) {
1246 throw std::range_error(
"sort column out of bounds");
1248 v[col]->template sort<AO>();
1252 template<
class UnaryFunction>
1253 UnaryFunction for_each(UnaryFunction f)
const {
1254 for (
auto& vi : v) {
1255 f = std::for_each(vi->begin(), vi->end(), f);
1262 template<
typename U,
typename AO=O>
1263 Array<U> sort_idx(idx_type base)
const {
1264 vector<unique_ptr<Vector<U>>> idxv;
1265 for (idx_type j=0; j<v.size(); ++j) {
1266 idxv.emplace_back(make_unique<Vector<U>>(v[j]->
template sort_idx<U, AO>(base)));
1268 return Array<U>(dim, idxv, names);
1272 Vector<idx_type> dim;
1275 vector<unique_ptr<Vector<T,O>>> v;
1278 std::unique_ptr<AllocFactory> allocf;
1284 template<
typename R,
typename T>
1287 for (
auto& e: u.v) {
1288 r.insert(r.end(), e->begin(), e->end());
1294 template<
typename R,
typename T>
1297 for (
auto& e: u.v) {
1298 r.insert(r.end(), e->begin(), e->end());
1307 template<
typename T>
1312 idx_type n = u.v.size() * u.dim[0];
1314 for (
auto& e: u.v) {
1315 r.v[0]->insert(r.v[0]->end(), e->begin(), e->end());
1322 inline Array<arr::zstring> vectorize(
const Array<arr::zstring>& u) {
1323 idx_type n = u.v.size() * u.dim[0];
1324 Array<zstring> r(rsv, {n});
1325 for (
auto& e: u.v) {
1326 for (
auto iter=e->begin(); iter!=e->end(); ++iter) {
1327 r.v[0]->push_back(*iter);
1334 template<
typename T,
typename O=std::less<T>>
1335 Array<T,O> transpose(
const Array<T,O>& t) {
1336 if (t.dim.size() == 1) {
1337 return Array<T,O>({1, t.dim[0]},
static_cast<Vector<T,O>
>(*t.v[0]), {{}, t.names[0]->names});
1339 else if (t.dim.size() == 2) {
1340 Array<T,O> a(noinit_tag,
1341 {t.getdim(1), t.getdim(0)}, {{t.getnames(1).names}, t.getnames(0).names});
1342 for (idx_type j=0; j<a.getdim(1); ++j)
1343 for (idx_type k=0; k<a.getdim(0); ++k)
1344 setv_checkbefore(a.getcol(j), k, t.getcol(k)[j]);
1348 throw range_error(
"argument is not a matrix");
1360 template<
typename T,
typename O=std::less<T>>
1361 Array<T,O>& drop(Array<T,O>& a) {
1362 auto di = a.dim.end()-1;
1363 auto ni = a.names.end()-1;
1364 for (; di > a.dim.begin(); --di, --ni) {
1373 template<
typename T,
typename R,
typename OT=std::less<T>,
typename OR=std::less<R>>
1374 Array<R,OR> applyf(
const Array<T,OT>& t,
function<R(T)> f) {
1375 auto ret = Array<R,OR>(rsv, t.dim);
1376 for (idx_type j=0; j<t.names.size(); ++j) {
1377 ret.names[j] = make_unique<Dname>(*t.names[j]);
1379 for (idx_type n=0; n<t.v.size(); ++n) {
1380 for (idx_type i=0; i<t.v[n]->size(); ++i) {
1381 ret.v[n]->push_back(f((*t.v[n])[i]));
1388 template<
typename T,
typename U,
typename R,
class F,
1389 typename OU=std::less<U>,
typename OR=std::less<R>>
1390 Array<R,OR> apply_scalar(T t,
const Array<U,OU>& u) {
1391 Array<R,OR> ret(rsv, u.dim);
1392 for (idx_type j=0; j<u.names.size(); ++j) {
1393 ret.names[j] = make_unique<Dname>(*u.names[j]);
1395 for (idx_type n=0; n<u.v.size(); ++n) {
1396 for (idx_type i=0; i<u.v[n]->size(); ++i) {
1397 ret.v[n]->push_back(F()(t, (*u.v[n])[i]));
1403 template<
typename U,
typename T,
typename R,
class F,
1404 typename OU=std::less<U>,
typename OR=std::less<R>>
1405 Array<R,OR> apply_scalar(
const Array<U,OU>& u, T t) {
1406 Array<R,OR> ret(rsv, u.dim);
1407 for (idx_type j=0; j<u.names.size(); ++j) {
1408 ret.names[j] = make_unique<Dname>(*u.names[j]);
1410 for (idx_type n=0; n<u.v.size(); ++n) {
1411 for (idx_type i=0; i<u.v[n]->size(); ++i) {
1412 ret.v[n]->push_back(F()((*u.v[n])[i], t));
1419 template <
typename T,
typename O>
1420 void setv_checkbefore(Array<T,O>& a, idx_type i, T t) {
1421 if (!a.dim.size())
throw range_error(
"subscript out of bounds");
1422 idx_type col = i / a.dim[0];
1423 idx_type off = i % a.dim[0];
1424 if (col >= a.ncols())
throw range_error(
"subscript out of bounds");
1425 setv_checkbefore(*a.v[col], off, t);
1428 template <
typename T,
typename O>
1429 void setv(Array<T,O>& a, idx_type i, T t) {
1430 if (!a.dim.size())
throw range_error(
"subscript out of bounds");
1431 idx_type col = i / a.dim[0];
1432 idx_type off = i % a.dim[0];
1433 if (col >= a.ncols())
throw range_error(
"subscript out of bounds");
1434 setv(*a.v[col], off, t);
1441 template<
typename F,
typename R,
typename O,
typename U1,
typename ...U>
1443 if (!
checksize(u1, u...))
throw std::out_of_range(
"size mismatch");
1447 for (idx_type j=0; j<u1.names.size(); ++j) {
1448 ret.names[j] = make_unique<Dname>(*u1.names[j]);
1450 for (idx_type n=0; n<u1.v.size(); ++n) {
1451 for (idx_type j=0; j<u1.v[n]->size(); ++j) {
1452 ret.v[n]->push_back(F()((*u1.v[n])[j], u[ii]...));
1459 template<
typename F,
typename R,
typename O,
typename U1,
typename ...U>
1460 Array<R,O> apply_samesize(
const U1 u1,
const U&... u) {
1461 if (!checkdims(u1, u...))
throw std::out_of_range(
"size mismatch");
1462 auto ret = Array<R,O>(rsv, u1.dim);
1463 for (idx_type j=0; j<u1.names.size(); ++j) {
1464 ret.names[j] = make_unique<Dname>(*u1.names[j]);
1466 for (idx_type n=0; n<u1.v.size(); ++n) {
1467 for (idx_type i=0; i<u1.v[n]->size(); ++i) {
1468 ret.v[n]->push_back(F()((u1->getcol[n])[i], (u->getcol[n])[i])...);
1474 template<
typename T,
typename U,
typename R,
class F,
1475 typename OT=std::less<T>,
typename OU=std::less<U>,
typename OR=std::less<R>>
1476 Array<R,OR>
apply(
const Array<T,OT>& t,
const Array<U,OU>& u) {
1477 if (t.size() == 1) {
1478 return apply_scalar<T,U,R,F,OU,OR>(t[0], u);
1480 else if (u.size() == 1) {
1481 return apply_scalar<T,U,R,F,OT,OR>(t, u[0]);
1486 if (t.dim != u.dim) {
1487 throw std::range_error(
"incompatible array sizes");
1489 auto ret = Array<R>(rsv, u.dim);
1491 for (idx_type j=0; j<u.names.size(); ++j) {
1492 ret.names[j] = make_unique<Dname>(t.hasNames(j) ? *t.names[j] : *u.names[j]);
1494 for (idx_type n=0; n<u.v.size(); ++n) {
1495 for (idx_type i=0; i<u.v[n]->size(); ++i) {
1496 ret.v[n]->push_back(F()((*t.v[n])[i], (*u.v[n])[i]));
1502 template<
typename T,
typename U,
typename R,
class F,
typename A,
1503 typename OU=std::less<U>,
typename OR=std::less<R>>
1504 Array<R,OR> apply_attrib_scalar_post(T t,
const Array<U,OU>& u,
const A& a) {
1505 Array<R,OR> ret(rsv, u.dim);
1506 for (idx_type j=0; j<u.names.size(); ++j) {
1507 ret.names[j] = make_unique<Dname>(*u.names[j]);
1509 for (idx_type n=0; n<u.v.size(); ++n) {
1510 for (idx_type i=0; i<u.v[n]->size(); ++i) {
1511 ret.v[n]->push_back(F()(t, (*u.v[n])[i], a));
1517 template<
typename U,
typename T,
typename R,
class F,
typename A,
1518 typename OU=std::less<U>,
typename OR=std::less<R>>
1519 Array<R,OR> apply_attrib_scalar_pre(
const Array<U,OU>& u, T t,
const A& a) {
1520 Array<R,OR> ret(rsv, u.dim);
1521 for (idx_type j=0; j<u.names.size(); ++j) {
1522 ret.names[j] = make_unique<Dname>(*u.names[j]);
1524 for (idx_type n=0; n<u.v.size(); ++n) {
1525 for (idx_type i=0; i<u.v[n]->size(); ++i) {
1526 ret.v[n]->push_back(F()((*u.v[n])[i], t, a));
1533 template<
typename T,
typename U,
typename R,
class F,
typename A,
1534 typename OT=std::less<T>,
typename OR=std::less<R>,
typename OU=std::less<U>>
1535 Array<R,OR> apply_attrib(
const Array<T,OT>& t,
const Array<U,OU>& u,
const A& a) {
1536 if (t.size() == 1) {
1537 return apply_attrib_scalar_post<T,U,R,F,A,OU,OR>(t[0], u, a);
1539 else if (u.size() == 1) {
1540 return apply_attrib_scalar_pre<T,U,R,F,A,OT,OR>(t, u[0], a);
1545 if (t.dim != u.dim) {
1546 throw std::range_error(
"incompatible array sizes");
1548 auto ret = Array<R,OR>(rsv, u.dim);
1549 for (idx_type j=0; j<u.names.size(); ++j) {
1550 ret.names[j] = make_unique<Dname>(t.hasNames(j) ? *t.names[j] : *u.names[j]);
1552 for (idx_type n=0; n<u.v.size(); ++n) {
1553 for (idx_type i=0; i<u.v[n]->size(); ++i) {
1554 ret.v[n]->push_back(F()((*t.v[n])[i], (*u.v[n])[i], a));
1560 template<
typename T,
typename O=std::less<T>>
1561 Array<T,O> maxcol(
const Array<T,O>& t) {
1563 Vector<idx_type> dim{1};
1564 dim.insert(dim.end(), t.dim.begin()+1, t.dim.end());
1565 Array<T,O> ret(rsv, dim);
1566 for (idx_type n=0; n<t.v.size(); ++n) {
1567 T maxelt = (*t.v[n])[0];
1568 for (
auto elt : *t.v[n]) {
1569 if (elt > maxelt) maxelt = elt;
1571 ret.v[n]->push_back(maxelt);
1576 template<
typename T,
typename R,
template <
class>
class F,
typename O=std::less<T>>
1577 R cumul(
const Array<T,O>& t,
const R& init) {
1579 for (idx_type n=0; n<t.v.size(); ++n) {
1580 for (idx_type i=0; i<t.v[n]->size(); ++i) {
1581 res = F<R>()(res, (*t.v[n])[i]);
1589 template<
typename T,
typename R,
template <
class>
class F,
typename O=std::less<T>>
1592 for (idx_type n=0; n<t.v.size(); ++n) {
1593 for (idx_type i=0; i<t.v[n]->size(); ++i) {
1594 res = F<R>()(res, (*t.v[n])[i]);
1604 template<
typename T,
typename O=std::less<T>>
1605 inline vector<T> toStdVector(
const Array<T,O>& a) {
1606 if (!a.isVector()) {
1607 throw out_of_range(
"multidimentional array cannot be converted to 'vector'");
1613 template<
typename T,
typename O=std::less<T>>
1617 throw std::out_of_range(
"array_from_vector: null array creation not supported");