forked from inakleinbottle/exponentiating_formulae
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathenvironment.h
180 lines (150 loc) · 6.63 KB
/
environment.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#pragma once
#include <functional>
#include <iostream>
#include <sstream>
#include <string>
#include <libalgebra/libalgebra.h>
using namespace alg;
template<DEG WIDTH, DEG DEPTH>
struct Environment {
using scalar_field = coefficients::rational_field;
using S = typename scalar_field::S;
static constexpr DEG WIDTH = WIDTH;
static constexpr DEG DEPTH = DEPTH;
static constexpr DEG poly_width = hall_basis<WIDTH, DEPTH>::start_of_degree(DEPTH + 1);
using poly_t = alg::poly<scalar_field>;
using poly_coeffs = coefficients::coefficient_ring<poly_t, typename scalar_field::Q>;
static_assert(std::is_same<poly_coeffs::S, poly_t>::value, "the trait class of a coefficient ring must report the type of the coefficients");
template<DEG DEPTH>
using LIE_ = alg::lie<poly_coeffs, WIDTH, DEPTH, vectors::dense_vector>;
using LIE = LIE_<DEPTH>;
template<DEG DEPTH>
using lie_basis_t_ = lie_basis<WIDTH, DEPTH>;
using lie_basis_t = lie_basis_t_<WIDTH>;
lie_basis_t lbasis;
template<DEG DEPTH>
using TENSOR_ = alg::free_tensor<poly_coeffs, WIDTH, DEPTH, vectors::dense_vector>;
using TENSOR = TENSOR_<DEPTH>;
template<DEG DEPTH>
using tensor_basis_t_ = alg::tensor_basis<WIDTH, DEPTH>;
using tensor_basis_t = tensor_basis_t_< DEPTH>;
tensor_basis_t tbasis;
//using SHUFFLE_TENSOR = alg::shuffle_tensor<scalar_field, WIDTH, DEPTH>;
template<DEG DEPTH>
using SHUFFLE_TENSOR_ = alg::shuffle_tensor<poly_coeffs, WIDTH, DEPTH>;
using SHUFFLE_TENSOR = SHUFFLE_TENSOR_<DEPTH>;
template<DEG DEPTH>
using shuffle_tensor_basis_t_ = alg::tensor_basis<WIDTH, DEPTH>;
using shuffle_tensor_basis_t = shuffle_tensor_basis_t_<DEPTH>;
shuffle_tensor_basis_t sbasis;
using SHUFFLE_TENSOR_OVER_POLYS = alg::shuffle_tensor<poly_coeffs, WIDTH, DEPTH>;
using inner_product = alg::operators::shuffle_tensor_functional<TENSOR, SHUFFLE_TENSOR_OVER_POLYS>;
using MAPS = maps<poly_coeffs, WIDTH, DEPTH, TENSOR, LIE>;
using CBH = cbh<poly_coeffs, WIDTH, DEPTH, TENSOR, LIE>;
MAPS maps_;
CBH cbh_;
// make a LIE element whose hall coefficients are monomials
LIE generic_lie(const int offset = 0) const
{
LIE result;
for (auto lie_key : lbasis.iterate_keys()) {
result.add_scal_prod(lie_key, poly_t(lie_key + offset, S(1)));
}
return result;
}
// The bilinear function K takes a shuffle and contracts it with a tensor to produce a scalar.
// In this case the scalar is itself a polynomial
static typename poly_coeffs::S K(const SHUFFLE_TENSOR& functional, const TENSOR& sig_data)
{
SHUFFLE_TENSOR_OVER_POLYS functional_p;
for (auto& key_value : functional)
functional_p.add_scal_prod(key_value.key(), typename poly_coeffs::S(key_value.value()));
inner_product f(sig_data);//todo: left and right switched here?
return f(functional_p);
}
// creates a generic vector with monomial coefficients
template<class VECTOR, const int offset0 = 0>
static VECTOR generic_vector(const int offset = offset0)
{
const typename VECTOR::BASIS& basis = VECTOR::basis;
// LIE basis starts at 1 which is confusing
int count;
if constexpr (std::is_integral<decltype(basis.begin())>::value) {
// invalid code if the premise is false - constexpr essential to avoid compilation
count = basis.begin();
}
else {
count = 0;
}
std::map<int, std::pair<typename VECTOR::KEY, std::string>> legend;
VECTOR result;
//for range type for loop approach use ": basis.iterate_keys()"
for (auto key = basis.begin(), end = basis.end(); key != end; key = basis.nextkey(key)) {
result[key] = poly_t(count + offset, 1);
// record the mapping from keys to monomials
auto basis_key_pair = std::pair<typename VECTOR::BASIS*, typename VECTOR::KEY>(&VECTOR::basis, key);
std::stringstream buffer;
buffer << basis_key_pair;
legend[count + offset] = std::pair(key, buffer.str());
std::cout << " monomial index: x" << count + offset << " basis index:" << key << " basis value:" << buffer.str() << "\n";
++count;
}
std::cout << "\n";
return result;
}
static SHUFFLE_TENSOR shift_down(const SHUFFLE_TENSOR& sh, typename SHUFFLE_TENSOR::KEY word)
{
typename SHUFFLE_TENSOR result(sh), working;
while (word.size()) {
auto letter = word.lparent();
word = word.rparent();
for (auto& pr : result) {
if (pr.key().lparent() == letter)
working[pr.key().rparent()] = result[pr.key()];
}
result.swap(working);
working.clear();
}
return result;
}
// the evaluation of the adjoint operation is worked out below
// <sh,ab>=\sum_{uv=sh}<ua><vb>
// = <\sum_{uv=sh}<ua>v,b>
// Let T_w(sh) be all the projection of sh onto the part beginning with w with w removed
// \sum_{i} <ki shi,ab> =
// = \sum_{i} ki<\sum_{uv=shi}<ua>v,b>
// = \sum_{u} < <ua>T_u(sh), b>
// The action of the adjoint of tensor multiplication by a multiplication is \sum_u <ua> T_u(sh)
static typename SHUFFLE_TENSOR adjoint_to_multiply(const TENSOR& t, SHUFFLE_TENSOR sh)
{
// this implementation is understandable and reliable but repetitive and can be radically accelerated
SHUFFLE_TENSOR result;
for (auto& pr : t) {
result += shift_down(sh, pr.key()) * pr.value();
}
return result;
}
};
template<class FULL_TENSOR, class SHORT_TENSOR>
FULL_TENSOR& add_equals_short(FULL_TENSOR& out, const SHORT_TENSOR& in)
{
const static typename FULL_TENSOR::BASIS fbasis;
const static typename SHORT_TENSOR::BASIS sbasis;
auto key = sbasis.begin(), end = sbasis.end();
auto fkey = fbasis.begin(), fend = fbasis.end();
for (; key != end && fkey != fend; key = sbasis.nextkey(key), fkey = fbasis.nextkey(fkey))
out[fkey] += in[key];
return out;
}
template<class EnvironmentOUT, class EnvironmentIN>
typename EnvironmentOUT::TENSOR apply1(const std::map<typename EnvironmentOUT::TENSOR::BASIS::KEY, typename EnvironmentIN::SHUFFLE_TENSOR>& result, const typename EnvironmentIN::TENSOR& in)
{
typename EnvironmentOUT::TENSOR out;
for (const auto& x : result) {
auto& key = x.first;
auto& tvalue = x.second;
// both environments must have compatible scalar types
out[key] = typename EnvironmentIN::K(tvalue, in);
};
return out;
}