19 auto& w =
shape->world();
23 auto r =
shape->num_projs();
24 for (
size_t i = 0, e = r; i != e; ++i) {
25 auto dim =
shape->proj(r, i);
27 if (dim_lit == 1)
continue;
30 index_dims.push_back(index->
proj(r, i));
33 assert(dims.size() == index_dims.size());
34 return std::make_tuple(dims.size(), w.tuple(dims), w.tuple(index_dims));
40 auto [index, arr] = arg->
projs<2>();
41 auto callee = c->as<
App>();
42 auto [T, r, s] = callee->args<3>();
44 w.log().d(
"get: arr = {}: {}, index = {}, T = {}, r = {}, s = {}", arr, arr->type(), index, T, r, s);
48 w.log().d(
"folded shape/index: r = {}, s = {}, index = {}", new_r, new_s, new_index);
49 if (new_r == 0)
return arr;
50 if (new_s != s || new_index != index)
return op_get(T, w.lit_nat(new_r), new_s, arr, new_index);
54 w.log().d(
"get after set: try bypass");
56 auto [target_index, _, x] =
set->args<3>();
57 if (target_index == index) {
58 w.log().d(
"bypassed");
63 w.log().d(
"get after get: try bypass");
65 auto [outer_index, outer_arr] =
get->args<2>();
66 auto [o_T, o_r, o_s] =
get->callee()->as<
App>()->args<3>();
67 w.log().d(
"outer: arr = {}: {}, index = {}, T = {}, r = {}, s = {}", outer_arr, outer_arr->type(), outer_index,
74 return op_get(T, new_r, new_s, outer_arr, new_index);
82 w.log().d(
"get after repeat: try bypass");
83 auto input = rep->arg();
84 auto [Tr, s_in, s_out] = rep->callee()->as<
App>()->uncurry_args<3>();
87 for (
u64 d = 0; d < *r_l; ++d) {
88 auto in_d = s_in->proj(*r_l, d);
89 auto idx_d = index->proj(*r_l, d);
90 if (in_d == s_out->proj(*r_l, d))
93 new_index[d] = w.lit_idx(1, 0);
95 new_index[d] = w.lit_idx(*e, *i % *e);
99 w.log().d(
"bypassed");
100 return op_get(T, Tr->
proj(2, 1), s_in, input, w.tuple(new_index));
108 w.log().d(
"get after broadcast: try bypass");
109 auto [s_in, s_out, input] = bc->args<3>();
110 auto [b_T, b_r] = bc->callee()->as<
App>()->args<2>();
113 for (
u64 d = 0; d < *r_l; ++d) {
114 auto in_d = s_in->proj(*r_l, d);
115 if (in_d == s_out->proj(*r_l, d))
116 new_index[d] = index->proj(*r_l, d);
118 new_index[d] = w.lit_idx(1, 0);
122 w.log().d(
"bypassed");
123 return op_get(T, b_r, s_in, input, w.tuple(new_index));
131 auto& w = c->world();
133 auto [index, arr, x] = arg->
projs<3>();
134 w.log().d(
"set: arr = {}: {}, index = {}, x = {}: {}", arr, arr->type(), index, x, x->type());
136 auto callee = c->as<
App>();
137 auto [T, r, s] = callee->args<3>();
141 w.log().d(
"folded shape/index: r = {}, s = {}, index = {}", new_r, new_s, new_index);
142 if (new_r == 0)
return x;
143 if (new_s != s || new_index != index)
return op_set(T, w.lit_nat(new_r), new_s, arr, new_index, x);
147 w.log().d(
"set after get: try bypass");
149 auto [inner_index, inner_arr] =
get->args<2>();
150 if (inner_arr == arr && inner_index == index) {
151 w.log().d(
"bypassed");
157 w.log().d(
"set after set: try bypass");
158 auto inner_set = x->as<
App>();
159 auto [inner_index, inner_arr, inner_x] = inner_set->args<3>();
160 auto [i_T, i_r, i_s] = inner_set->
callee()->as<
App>()->args<3>();
162 w.log().d(
"inner: arr = {}: {}, index = {}, x = {}, T = {}, r = {}, s = {}", inner_arr, inner_arr->
type(),
163 inner_index, inner_x, i_T, i_r, i_s);
166 auto [g_index, g_arr] = inner_get->args<2>();
167 if (g_arr == arr && g_index == index) {
172 return op_set(i_T, new_r, new_s, arr, new_index, inner_x);
175 w.log().d(
"no bypass: inner arr is not get(arr, index)");
177 w.log().d(
"no normalization applicable");
182 auto& w = c->world();
184 auto [s_in, s_out, input] = arg->
projs<3>();
185 auto callee = c->as<
App>();
186 auto [T, r] = callee->args<2>();
187 w.log().d(
"broadcast: input = {}: {}, T = {}, r = {}, s_in = {}, s_out = {}", input, input->type(), T, r, s_in,
190 if (s_in == s_out)
return input;
193 if (!r_nat)
return nullptr;
194 if (r_nat == 0)
return input;
203 auto [Tr, s_in, s_out] = c->as<
App>()->uncurry_args<3>();
204 if (s_in == s_out)
return arg;
210 auto [Trr, s_in, s_out] = c->as<
App>()->uncurry_args<3>();
211 if (s_in == s_out)
return arg;
217 auto [Tr, s_in, params] = c->as<
App>()->uncurry_args<3>();
218 auto [start, step, s_out] = params->projs<3>();
219 if (s_out != s_in)
return nullptr;
221 if (!r)
return nullptr;
222 for (
u64 d = 0; d != *r; ++d) {
225 if (!st || *st != 0 || !sp || *sp != 1)
return nullptr;
234 auto [Tr, s_in, params] = c->as<
App>()->uncurry_args<3>();
235 auto [mode, lo, hi] = params->projs<3>();
237 if (!r)
return nullptr;
238 for (
u64 d = 0; d != *r; ++d) {
241 if (!l || *l != 0 || !h || *h != 0)
return nullptr;
243 return arg->
proj(2, 0);
252 auto [k, s, d] = arg->
projs<3>();
264 auto& w = arg->
world();
265 auto [r, t] = arg->
projs<2>();
267 if (!r_l || *r_l == 0)
return r;
269 if (!pr)
return w.lit_nat(*r_l - 1);
273 if (!r_src || *r_src == 0)
return r;
276 if (!r_dom || *r_dom != *r_l)
return r;
278 auto markers =
DefVec(*r_l, [&](
size_t i) {
return w.call<
affine::lit>(w.lit_nat(i + 1)); });
279 auto last = w.app(pr->map, w.tuple(markers))->proj(*r_src, *r_src - 1);
283 if (!v || *v < 1 || *v > *r_l)
return r;
284 return w.lit_nat(*v - 1);
289 auto& w = c->world();
291 if (!r)
return nullptr;
294 auto ty = arg->
type();
295 for (
u64 i = 0; i != *r; ++i)
296 if (
auto a = ty->isa<
Seq>()) {
297 dims.emplace_back(a->arity());
301 return w.tuple(dims);
const Def * callee() const
static auto isa(const Def *def)
const Def * proj(nat_t a, nat_t i) const
Similar to World::extract while assuming an arity of a, but also works on Sigmas and Arrays.
World & world() const noexcept
auto projs(F f) const
Splits this Def via Def::projections into an Array (if A == std::dynamic_extent) or std::array (other...
const Def * type() const noexcept
Yields the "raw" type of this Def (maybe nullptr).
const Def * arity() const
Number of elements available to Extract / Insert (may be dynamic).
static std::optional< T > isa(const Def *def)
A dependent function type.
const Def * codom() const
Base class for Arr and Pack.
const Def * normalize_broadcast(const Def *, const Def *c, const Def *arg)
const Def * normalize_if_static(const Def *, const Def *, const Def *arg)
const Def * normalize_slice(const Def *, const Def *c, const Def *arg)
const Def * normalize_repeat(const Def *, const Def *c, const Def *arg)
const Def * op_set(const Def *T, const Def *r, const Def *s, const Def *arr, const Def *index, const Def *x)
const Def * normalize_pad(const Def *, const Def *c, const Def *arg)
const Def * normalize_get(const Def *, const Def *c, const Def *arg)
const Def * normalize_broadcast_in_dim(const Def *, const Def *, const Def *)
std::optional< PureRead > is_pure_read(const Def *value)
If value is a pure re-indexed read — a copy-combiner map_reduce without reduction loops that writes i...
std::tuple< u64, const Def *, const Def * > fold_shape_and_index(const Def *shape, const Def *index)
const Def * normalize_set(const Def *, const Def *c, const Def *arg)
const Def * normalize_concat(const Def *, const Def *, const Def *)
const Def * normalize_fastest_axis(const Def *, const Def *, const Def *arg)
const Def * normalize_reshape(const Def *, const Def *c, const Def *arg)
const Def * normalize_shape(const Def *, const Def *c, const Def *arg)
const Def * normalize_flip(const Def *, const Def *, const Def *)
const Def * op_get(const Def *T, const Def *r, const Def *s, const Def *arr, const Def *index)
fe::Vector< const Def * > DefVec
#define MIM_tensor_NORMALIZER_IMPL