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 9686 : Variable islinspace(const Variable &var, const Dim dim) {
47 9686 : const auto con_var = as_contiguous(var, dim);
48 19372 : return transform(subspan_view(con_var, dim), core::element::islinspace,
49 29058 : "islinspace");
50 9686 : }
51 :
52 4831 : Variable isarange(const Variable &var, const Dim dim) {
53 9662 : 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 10754 : Variable issorted(const Variable &x, const Dim dim, const SortOrder order) {
61 10754 : auto dims = x.dims();
62 10754 : dims.erase(dim);
63 10752 : auto out = variable::ones(dims, units::none, dtype<bool>);
64 10752 : const auto size = x.dims()[dim];
65 10752 : if (size < 2)
66 69 : return out;
67 10683 : if (order == SortOrder::Ascending)
68 20886 : accumulate_in_place(out, x.slice({dim, 0, size - 1}),
69 20886 : x.slice({dim, 1, size}),
70 : core::element::issorted_nondescending, "issorted");
71 : else
72 480 : accumulate_in_place(out, x.slice({dim, 0, size - 1}),
73 480 : x.slice({dim, 1, size}),
74 : core::element::issorted_nonascending, "issorted");
75 10683 : return out;
76 10754 : }
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 10741 : bool allsorted(const Variable &x, const Dim dim, const SortOrder order) {
83 10741 : 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 248921 : Variable zip(const Variable &first, const Variable &second) {
88 497842 : return transform(astype(first, dtype<int64_t>, CopyPolicy::TryAvoid),
89 497842 : astype(second, dtype<int64_t>, CopyPolicy::TryAvoid),
90 746763 : 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 20424 : std::pair<Variable, Variable> unzip(const Variable &var) {
96 40848 : return {var.elements<scipp::index_pair>("begin"),
97 40848 : 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 21724 : void fill_zeros(Variable &var) {
107 21724 : transform_in_place(var, core::element::fill_zeros, "fill_zeros");
108 21724 : }
109 :
110 : /// Return elements chosen from x or y depending on condition.
111 2476 : Variable where(const Variable &condition, const Variable &x,
112 : const Variable &y) {
113 2476 : return variable::transform(condition, x, y, element::where, "where");
114 : }
115 :
116 165857 : Variable as_contiguous(const Variable &var, const Dim dim) {
117 165857 : if (var.stride(dim) == 1)
118 165831 : return var;
119 26 : auto dims = var.dims();
120 26 : dims.erase(dim);
121 26 : dims.addInner(dim, var.dims()[dim]);
122 52 : return copy(transpose(var, dims.labels()));
123 26 : }
124 :
125 : } // namespace scipp::variable
|