IgANet
IGAnets - Isogeometric Analysis Networks
Loading...
Searching...
No Matches
vslice.hpp
Go to the documentation of this file.
1
15#pragma once
16
17#include <array>
18#include <stdexcept>
19
20#include <iganet/core/core.hpp>
23
24namespace iganet::utils {
25
47template <bool transpose = false>
48inline auto VSlice(torch::Tensor index, int64_t start_offset,
49 int64_t stop_offset) {
50 if (stop_offset <= start_offset)
51 throw std::invalid_argument(
52 "VSlice requires stop_offset to be greater than start_offset");
53
54 if constexpr (transpose)
55 return index.repeat_interleave(stop_offset - start_offset) +
56 torch::linspace(start_offset, stop_offset - 1,
57 stop_offset - start_offset, index.options())
58 .repeat(index.numel());
59 else
60 return index.repeat(stop_offset - start_offset) +
61 torch::linspace(start_offset, stop_offset - 1,
62 stop_offset - start_offset, index.options())
63 .repeat_interleave(index.numel());
64}
65
79template <bool transpose = false, std::size_t N>
80inline auto VSlice(const utils::TensorArray<N> &index,
81 const std::array<int64_t, N> &start_offset,
82 const std::array<int64_t, N> &stop_offset,
83 const std::array<int64_t, N - 1> &leading_dim =
84 make_array<int64_t, N - 1>(1)) {
85
86 // Check compatibility of arguments
87 for (std::size_t i = 1; i < N; ++i)
88 if (index[i - 1].numel() != index[i].numel())
89 throw std::invalid_argument(
90 "VSlice requires index tensors with equal lengths");
91
92 for (std::size_t i = 0; i < N; ++i)
93 if (stop_offset[i] <= start_offset[i])
94 throw std::invalid_argument(
95 "VSlice requires every stop offset to exceed its start offset");
96
97 auto dist = stop_offset - start_offset;
98
99 if constexpr (transpose) {
100
101 // Lambda expression to evaluate the k-th summand of the vslice
102 auto vslice_summand_ = [&](std::size_t k) {
103 if (k == N - 1) {
104 return (index[k].repeat_interleave(utils::prod(dist, 0, k)) +
105 torch::linspace(start_offset[k], stop_offset[k] - 1, dist[k],
106 index[0].options())
107 .repeat_interleave(utils::prod(dist, 0, k - 1))
108 .repeat(index[0].numel())) *
109 utils::prod(leading_dim, 0, k - 1);
110 } else if (k == 0) {
111 if constexpr (N == 2) {
112 return index[0].repeat_interleave(dist[0]).repeat_interleave(
113 dist[1]) +
114 torch::linspace(start_offset[0], stop_offset[0] - 1, dist[0],
115 index[0].options())
116 .repeat(index[1].numel())
117 .repeat(dist[1]);
118 } else { // N > 2
119 return index[0].repeat_interleave(dist[0]).repeat_interleave(
120 utils::prod(dist, 1, N - 1)) +
121 torch::linspace(start_offset[0], stop_offset[0] - 1, dist[0],
122 index[0].options())
123 .repeat(index[0].numel())
124 .repeat(utils::prod(dist, 1, N - 1));
125 }
126 } else {
127 return (index[k]
128 .repeat_interleave(utils::prod(dist, 0, k))
129 .repeat_interleave(utils::prod(dist, k + 1, N - 1)) +
130 torch::linspace(start_offset[k], stop_offset[k] - 1, dist[k],
131 index[0].options())
132 .repeat_interleave(utils::prod(dist, 0, k - 1))
133 .repeat(index[0].numel())
134 .repeat(utils::prod(dist, k + 1, N - 1))) *
135 utils::prod(leading_dim, 0, k - 1);
136 }
137 };
138
139 // Lambda expression to evaluate the vslice
140 auto vslice_ = [&]<std::size_t... Is>(std::index_sequence<Is...>) {
141 return (vslice_summand_(Is) + ...);
142 };
143
144 return vslice_(std::make_index_sequence<N>{});
145 } else {
146
147 // Lambda expression to evaluate the k-th summand of the vslice
148 auto vslice_summand_ = [&](std::size_t k) {
149 if (k == N - 1) {
150 return (index[k].repeat(utils::prod(dist, 0, k)) +
151 torch::linspace(start_offset[k], stop_offset[k] - 1, dist[k],
152 index[0].options())
153 .repeat_interleave(index[0].numel() *
154 utils::prod(dist, 0, k - 1))) *
155 utils::prod(leading_dim, 0, k - 1);
156 } else if (k == 0) {
157 if constexpr (N == 2) {
158 return (index[0].repeat(dist[0]) +
159 torch::linspace(start_offset[0], stop_offset[0] - 1, dist[0],
160 index[0].options())
161 .repeat_interleave(index[0].numel()))
162 .repeat(utils::prod(dist, k + 1, N - 1));
163 } else { // N > 2
164 return (index[0].repeat(dist[0]) +
165 torch::linspace(start_offset[0], stop_offset[0] - 1, dist[0],
166 index[0].options())
167 .repeat_interleave(index[0].numel()))
168 .repeat(utils::prod(dist, k + 1, N - 1));
169 }
170 } else {
171 return (index[k].repeat(utils::prod(dist, 0, k)) +
172 torch::linspace(start_offset[k], stop_offset[k] - 1, dist[k],
173 index[0].options())
174 .repeat_interleave(index[0].numel() *
175 utils::prod(dist, 0, k - 1)))
176 .repeat(utils::prod(dist, k + 1, N - 1)) *
177 utils::prod(leading_dim, 0, k - 1);
178 }
179 };
180
181 // Lambda expression to evaluate the vslice
182 auto vslice_ = [&]<std::size_t... Is>(std::index_sequence<Is...>) {
183 return (vslice_summand_(Is) + ...);
184 };
185
186 return vslice_(std::make_index_sequence<N>{});
187 }
188}
189
190} // namespace iganet::utils
Core components.
Linear algebra utility functions.
Definition blocktensor.hpp:24
std::array< torch::Tensor, N > TensorArray
Definition tensorarray.hpp:26
T prod(std::array< T, N > array, std::size_t start_index=0, std::size_t stop_index=N - 1)
Computes the (partial) product of all std::array entries.
Definition linalg.hpp:239
auto VSlice(torch::Tensor index, int64_t start_offset, int64_t stop_offset)
Vectorized version of torch::indexing::Slice (see https://pytorch.org/cppdocs/notes/tensor_indexing....
Definition vslice.hpp:48
TensorArray utility functions.