15std::optional<DefVec> elems(
const Def* n,
const Def*
vec) {
17 if (l == 0)
return DefVec();
21 if (
auto a =
Lit::isa(seq->arity()))
return seq->projs(*a);
32 if constexpr (
id ==
fold::r) std::swap(acc,
vec);
34 auto es = elems(n,
vec);
35 if (!es)
return nullptr;
39 acc = w.app(f, {acc, e});
41 for (
auto e : *es | std::views::reverse)
42 acc = w.app(f, {e, acc});
48 auto& w = type->world();
50 auto [ni, n] = ni_n->projs<2>([](
const Def* def) {
return Lit::isa(def); });
52 if (!ni || !n)
return {};
53 if (ni >= w.flags().scalarize_threshold || n >= w.flags().scalarize_threshold)
return {};
55 auto res = fe::Vector<const Def*, 32>(*n);
56 auto tup = fe::Vector<const Def*, 32>(*ni);
58 for (
size_t j = 0; j != n; ++j) {
59 for (
size_t i = 0; i != ni; ++i)
60 tup[i] = arg->
proj(*ni, i)->
proj(*n, j);
62 res[j] = w.app(f, tup);
75 if (
auto pack =
vec->isa_imm<
Pack>()) {
76 auto shape = pack->shape();
77 auto r = shape.rank();
78 if (!r)
return nullptr;
80 auto res = w.app(p, pack->body());
81 for (
nat_t i = 0; i != *r; ++i) {
90 auto es = elems(n,
vec);
91 if (!es)
return nullptr;
100 auto& w =
vec->world();
102 if (n && *n <= 1)
return w.lit_tt();
106 for (
auto op :
tuple->ops()) {
107 auto [_, ins] = seen.emplace(op);
108 if (!ins)
return w.lit_ff();
110 return tuple->is_closed() ? w.lit_tt() :
nullptr;
113 if (
auto pack =
vec->isa_imm<
Pack>()) {
114 if (
Lit::isa(pack->arity()))
return w.lit_ff();
121 auto [a, b] = arg->
projs<2>();
122 auto [n, m] = callee->as<
App>()->decurry()->
args<2>([](
auto def) {
return Lit::isa(def); });
123 if (n && *n == 0)
return b;
124 if (m && *m == 0)
return a;
125 return n && m ?
Tuple::cat(*n, *m, a, b) :
nullptr;
129 if (
auto arr = type->isa<
Arr>()) {
130 if (arr->arity()->isa<
Bot>())
return nullptr;
133 auto& w = type->world();
134 auto callee = c->as<
App>();
135 auto [n, m] = callee->
args<2>([](
auto def) {
return Lit::isa(def); });
138 if (!n || !m)
return nullptr;
139 if (n == 1 && m == 1)
return w.tuple();
141 if (
auto tup_vec =
vec->isa<
Tuple>()) {
142 if (
auto tup_is = is->isa<
Tuple>(); tup_is && tup_is->
is_closed()) {
144 auto drop = fe::Bitset();
145 for (
auto opi : tup_is->ops())
148 for (
size_t i = 0, e = tup_vec->num_ops(); i != e; ++i)
149 if (!drop.test(i)) defs.emplace_back(tup_vec->op(i));
150 return w.tuple(defs);
155 for (
size_t i = 0, e = tup_vec->num_ops(); i != e; ++i)
156 if (i != lit_is) defs.emplace_back(tup_vec->op(i));
157 return w.tuple(defs);
161 if (
auto tup_pack =
vec->isa_imm<
Pack>())
return w.pack(*n - *m, tup_pack->body());
auto args(Projector auto f) const noexcept
auto uncurry_args() const
A (possibly paramterized) Array.
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.
bool is_open() const
Same as has_free_vars().
auto projs(Projector auto f) const
Splits this Def via Def::projections into an Array (if A == std::dynamic_extent) or std::array (other...
bool is_closed() const
Same as !has_free_vars().
static std::optional< T > isa(const Def *def)
static T as(const Def *def)
A (possibly paramterized) Tuple.
Base class for Arr and Pack.
bool is_fused() const
Does this span several axes? Also true for a dynamic rank.
Data constructor for a Sigma.
static const Def * cat(nat_t n, nat_t m, const Def *a, const Def *b)
const Def * normalize_scan(const Def *, const Def *c, const Def *vec)
const Def * normalize_is_unique(const Def *, const Def *callee, const Def *vec)
const Def * normalize_cat(const Def *, const Def *callee, const Def *arg)
const Def * normalize_diff(const Def *type, const Def *c, const Def *arg)
const Def * normalize_fold(const Def *, const Def *c, const Def *arg)
const Def * normalize_zip(const Def *type, const Def *c, const Def *arg)
fe::View< const Def * > Defs
fe::Vector< const Def * > DefVec
GIDSet< const Def * > DefSet
#define MIM_vec_NORMALIZER_IMPL