Line data Source code
1 : // SPDX-License-Identifier: BSD-3-Clause
2 : // Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
3 : /// @file
4 : /// @author Simon Heybrock
5 : #include "scipp/variable/util.h"
6 : #include "scipp/core/element/util.h"
7 : #include "scipp/core/except.h"
8 : #include "scipp/variable/accumulate.h"
9 : #include "scipp/variable/arithmetic.h"
10 : #include "scipp/variable/astype.h"
11 : #include "scipp/variable/reduction.h"
12 : #include "scipp/variable/subspan_view.h"
13 : #include "scipp/variable/transform.h"
14 :
15 : using namespace scipp::core;
16 :
17 : namespace scipp::variable {
18 :
19 49 : Variable linspace(const Variable &start, const Variable &stop, const Dim dim,
20 : const scipp::index num) {
21 : // The implementation here is slightly verbose and explicit. It could be
22 : // improved if we were to introduce new variants of `transform`, similar to
23 : // `std::generate`.
24 51 : core::expect::equals(start.dims(), stop.dims());
25 50 : core::expect::equals(start.unit(), stop.unit());
26 49 : core::expect::equals(start.dtype(), stop.dtype());
27 46 : if (start.dtype() != dtype<double> && start.dtype() != dtype<float>)
28 1 : throw except::TypeError(
29 2 : "Cannot create linspace with non-floating-point start and/or stop.");
30 45 : if (start.has_variances() || stop.has_variances())
31 3 : throw except::VariancesError(
32 6 : "Cannot create linspace with start and/or stop containing variances.");
33 42 : auto dims = start.dims();
34 42 : dims.addInner(dim, num);
35 42 : Variable out(start, dims);
36 42 : const auto range = stop - start;
37 72143 : for (scipp::index i = 0; i < num - 1; ++i)
38 216303 : copy(start + astype(static_cast<double>(i) / (num - 1) * units::one,
39 144202 : start.dtype()) *
40 : range,
41 144202 : out.slice({dim, i}));
42 42 : copy(stop, out.slice({dim, num - 1})); // endpoint included
43 84 : return out;
44 42 : }
45 :
46 9818 : Variable islinspace(const Variable &var, const Dim dim) {
47 9818 : const auto con_var = as_contiguous(var, dim);
48 19636 : return transform(subspan_view(con_var, dim), core::element::islinspace,
49 29454 : "islinspace");
50 9818 : }
51 :
52 4803 : Variable isarange(const Variable &var, const Dim dim) {
53 9606 : return transform(subspan_view(var, dim), core::element::isarange, "isarange");
54 : }
55 :
56 : /// Return a variable of True, if variable values are sorted along given dim.
57 : ///
58 : /// If `order` is SortOrder::Ascending, checks if values are non-decreasing.
59 : /// If `order` is SortOrder::Descending, checks if values are non-increasing.
60 10868 : Variable issorted(const Variable &x, const Dim dim, const SortOrder order) {
61 10868 : auto dims = x.dims();
62 10868 : dims.erase(dim);
63 10866 : auto out = variable::ones(dims, units::none, dtype<bool>);
64 10866 : const auto size = x.dims()[dim];
65 10866 : if (size < 2)
66 69 : return out;
67 10797 : if (order == SortOrder::Ascending)
68 21108 : accumulate_in_place(out, x.slice({dim, 0, size - 1}),
69 21108 : x.slice({dim, 1, size}),
70 : core::element::issorted_nondescending, "issorted");
71 : else
72 486 : accumulate_in_place(out, x.slice({dim, 0, size - 1}),
73 486 : x.slice({dim, 1, size}),
74 : core::element::issorted_nonascending, "issorted");
75 10797 : return out;
76 10868 : }
77 :
78 : /// Return true if variable values are sorted along given dim.
79 : ///
80 : /// If `order` is SortOrder::Ascending, checks if values are non-decreasing.
81 : /// If `order` is SortOrder::Descending, checks if values are non-increasing.
82 10855 : bool allsorted(const Variable &x, const Dim dim, const SortOrder order) {
83 10855 : return variable::all(issorted(x, dim, order)).value<bool>();
84 : }
85 :
86 : /// Zip elements of two variables into a variable where each element is a pair.
87 250507 : Variable zip(const Variable &first, const Variable &second) {
88 501014 : return transform(astype(first, dtype<int64_t>, CopyPolicy::TryAvoid),
89 501014 : astype(second, dtype<int64_t>, CopyPolicy::TryAvoid),
90 751521 : core::element::zip, "zip");
91 : }
92 :
93 : /// For an input where elements are pairs, return two variables containing the
94 : /// first and second components of the input pairs.
95 22124 : std::pair<Variable, Variable> unzip(const Variable &var) {
96 44248 : return {var.elements<scipp::index_pair>("begin"),
97 44248 : var.elements<scipp::index_pair>("end")};
98 : }
99 :
100 : /// Fill variable with given values (and variances) and unit.
101 0 : void fill(Variable &var, const Variable &value) {
102 0 : transform_in_place(var, value, core::element::fill, "fill");
103 0 : }
104 :
105 : /// Fill variable with zeros.
106 22052 : void fill_zeros(Variable &var) {
107 22052 : transform_in_place(var, core::element::fill_zeros, "fill_zeros");
108 22052 : }
109 :
110 : /// Return elements chosen from x or y depending on condition.
111 3218 : Variable where(const Variable &condition, const Variable &x,
112 : const Variable &y) {
113 3218 : return variable::transform(condition, x, y, element::where, "where");
114 : }
115 :
116 166216 : Variable as_contiguous(const Variable &var, const Dim dim) {
117 166216 : if (var.stride(dim) == 1)
118 166175 : return var;
119 41 : auto dims = var.dims();
120 41 : dims.erase(dim);
121 41 : dims.addInner(dim, var.dims()[dim]);
122 82 : return copy(transpose(var, dims.labels()));
123 41 : }
124 :
125 : } // namespace scipp::variable
|