carl  24.04
Computer ARithmetic Library
MultiplicationTable.h
Go to the documentation of this file.
1 /*
2  * File: MultiplicationTable2.h
3  * Author: tobias
4  *
5  * Created on 8. August 2016, 14:32
6  */
7 
8 #pragma once
9 
10 #include "GroebnerBase.h"
11 
13 
14 namespace carl {
15 
16 
17 /*
18  * these objects represent elements from a certain vector space as a linear combinations of its base.
19  * rather than storing the elements in the base we only store indices.
20  */
21 template<typename Number>
22 struct BaseRepresentation : public std::map<uint, Number> {
24 
25  BaseRepresentation() = default;
26 
27  BaseRepresentation(const std::vector<Monomial>& base, const MultivariatePolynomial<Number>& p) {
28  CARL_LOG_ASSERT("carl.thom.tarski", base.size() >= p.size(), "p is not in <base>");
29  for(const auto& term : p) {
30  for(uint i = 0; i < base.size(); i++) {
31  if(term.monomial() == base[i].monomial()) {
32  this->insert(std::make_pair(i, term.coeff()));
33  }
34  }
35  }
36  }
37 
38  bool is_zero() const { return this->empty(); }
39  bool contains(uint i) const { return this->find(i) != this->end(); }
40  Number get(uint index) const {
41  auto it = this->find(index);
42  if(it == this->end()) return Number(0);
43  else return it->second;
44  }
45 };
46 
47 /*
48  * Let Mon be the base of the structure Q[x_1,...x_n] / <gb> viewed as a Q vector space
49  * this class stores for each monomial m in {ab | a,b in Mon } the following entry:
50  *
51  * Monomial | BaseRepresentation | Index pairs
52  *
53  * where the base representation is the monomial viewed as a linear combination of the basis
54  * and index pairs stores a list of all pairs of basis elements whose product is equal to Monomial
55  */
56 template<typename Number>
58 
59 public:
60 
61  using IndexPairs = std::forward_list<std::pair<uint, uint>>;
63 
64  struct TableContent {
67  };
68 private:
69 
70  // main datastructure
71  std::unordered_map<Monomial, TableContent> mTable;
72 
73  // the base of the factor ring as a vector space
74  std::vector<Monomial> mBase;
75 
76  // the groebner base object is used to compute reductions
78 
79 public:
80 
82 
83  explicit MultiplicationTable(const GroebnerBase<Number>& gb) : mGb(gb){
84  CARL_LOG_ASSERT("carl.thom.tarski.table", gb.hasFiniteMon(), "tried to set up a multiplication table on infinite basis");
85  init(gb);
86  CARL_LOG_TRACE("carl.thom.tarski.table", "done setting up multiplication table:\n" << *this);
87  }
88 
89  typename std::unordered_map<Monomial, TableContent>::const_iterator begin() const { return mTable.cbegin(); }
90  typename std::unordered_map<Monomial, TableContent>::const_iterator end() const { return mTable.cend(); }
91  typename std::unordered_map<Monomial, TableContent>::const_iterator cbegin() const { return mTable.cbegin(); }
92  typename std::unordered_map<Monomial, TableContent>::const_iterator cend() const { return mTable.cend(); }
93 
94 
95  inline bool contains(const Monomial& m) const {
96  return mTable.find(m) != mTable.end();
97  }
98 
99  const std::vector<Monomial>& getBase() const noexcept {
100  return mBase;
101  }
102 
104  return BaseRepresentation<Number>(mBase, mGb.reduce(p));
105  }
106 
107  const TableContent& getEntry(const Monomial& mon) const {
108  auto it = mTable.find(mon);
109  assert(it != mTable.end());
110  return it->second;
111  }
112 
114  MultivariatePolynomial<Number> res(Number(0));
115  for(const auto& entry : baseRepr) {
116  res += entry.second * this->mBase[entry.first];
117  }
118  return res;
119  }
120 
123  for(const auto& entry : this->mTable) {
124  if(entry.second.br.is_zero()) continue;
125  for(const auto& index_coeff : entry.second.br) {
126  Number newCoeff(0);
127  for(const auto& pair : entry.second.pairs) {
128  newCoeff += f.get(pair.first) * g.get(pair.second);
129  }
130  if(newCoeff != 0) {
131  res[index_coeff.first] += newCoeff * index_coeff.second;
132  }
133  }
134  }
135  return res;
136  }
137 
138 
139  Number trace(const BaseRepresentation<Number>& f) const {
140  Number res(0);
141  for(const auto& index_coeff : f) {
142  for(uint i = 0; i < mBase.size(); i++) {
143  Monomial prod = mBase[index_coeff.first] * mBase[i];
144  BaseRepresentation<Number> prod_br = this->getEntry(prod).br;
145  res += index_coeff.second * prod_br.get(i);
146  }
147  }
148  return res;
149  }
150 
151  template<typename C>
152  friend std::ostream& operator<<(std::ostream& o, const MultiplicationTable<C>& table);
153 
154 private:
155 
156  // returns a list of all pairs of indicdes (i,j) such that base_i * base_j == c
157  IndexPairs indexPairs(const Monomial& c) const {
158  IndexPairs res;
159  for(uint i = 0; i < mBase.size(); i++) {
160  for(uint j = i; j < mBase.size(); j++) {
161  if(mBase[i] * mBase[j] == c) {
162  res.push_front(std::make_pair(i, j));
163  if(i != j) res.push_front(std::make_pair(j, i));
164  }
165  }
166  }
167  return res;
168  }
169 
170  void init(const GroebnerBase<Number>& gb) {
171  CARL_LOG_FUNC("carl.thom.tarski", "gb = " << gb.get());
172 
173  // some needed values
174  std::vector<Monomial> Cor = gb.cor();
175  std::vector<Monomial> Bor = gb.bor();
176  std::vector<Monomial> Mon = gb.mon();
177  std::set<Variable> vars = gb.gatherVariables();
178 
179  // sort the base
180  std::sort(Mon.begin(), Mon.end());
181  mBase = Mon;
182 
183  // monomials in bor in increasing order
184  std::sort(Bor.begin(), Bor.end());
185 
186  // ---- step 0 ---- (not explicitly mentioned)
187  // put BaseReprensentation of the monomials from Mon itself in table
188  for(uint i = 0; i < Mon.size(); i++) {
190  baseRepr[i] = Number(1);
191  mTable[Mon[i]] = {baseRepr, indexPairs(Mon[i])};
192  }
193 
194  // ---- step 1 ----
195  // compute the normal forms of the elements in Bor
196  for(const auto& m : Bor) {
197  if(std::find(Cor.begin(), Cor.end(), m) != Cor.end()) {
198  CARL_LOG_TRACE("carl.thom.tarski.table", "in bor and also in cor: " << m);
199  // the monomial is also in Cor
200  // find the polynomial in the basis with the corresponding leading monomial
202  for(const auto& p : gb.get()) {
203  assert(!carl::is_zero(p));
204  if(p.lterm() == m) {
205  G = p;
206  break;
207  }
208  }
210  diff *= Number(-1);
211  BaseRepresentation<Number> baseRepr(mBase, diff);
212  IndexPairs pairs;
213  if(!baseRepr.is_zero()) {
214  pairs = indexPairs(m);
215  }
216  mTable[m] = {baseRepr, pairs};
217  //CARL_LOG_TRACE("carl.thom.tarski", "mTable = " << mTable);
218  }
219  else {
220  // try to find a variable X_j, such that m / X_j is in Bor
221  CARL_LOG_TRACE("carl.thom.tarski.table", "not in cor but in bor: " << m);
222  auto it = vars.begin();
223  Variable var = *it;
224  Monomial x_beta;
225  while(!try_divide(m, var, x_beta) || (std::find(Bor.begin(), Bor.end(), x_beta) == Bor.end())) {
226  it++;
227  CARL_LOG_ASSERT("carl.thom.tarski.table", it != vars.end(), "");
228  var = *it;
229  }
230  CARL_LOG_ASSERT("carl.thom.tarski.table", std::find(Bor.begin(), Bor.end(), x_beta) != Bor.end(), "");
231  CARL_LOG_TRACE("carl.thom.tarski.table", "x_beta = " << x_beta);
232  CARL_LOG_TRACE("carl.thom.tarski.table", "var = " << var);
233  CARL_LOG_ASSERT("carl.thom.tarski.table", this->contains(x_beta), "");
234  CARL_LOG_ASSERT("carl.thom.tarski.table", x_beta < m, "");
235 
236  BaseRepresentation<Number> nf_x_beta = mTable[x_beta].br;
237  MultivariatePolynomial<Number> sum(Number(0));
238 
239  // sum over all pairs in Mon^2...
240  CARL_LOG_TRACE("carl.thom.tarski.table", "nf_x_beta" << nf_x_beta);
241  for(const auto& entry_beta : nf_x_beta) {
242  Monomial x_gamma_prime = var * Mon[entry_beta.first];
243  CARL_LOG_ASSERT("carl.thom.tarski.table", x_gamma_prime < m, "");
244  CARL_LOG_ASSERT("carl.thom.tarski.table", this->contains(x_gamma_prime), "");
245  BaseRepresentation<Number> nf_x_gamma_prime = mTable[x_gamma_prime].br;
246  CARL_LOG_TRACE("carl.thom.tarski.table", "nf_x_gamma_prime" << nf_x_gamma_prime);
247  for(const auto& entry_gamma : nf_x_gamma_prime) {
248  Term<Number> prod(nf_x_beta[entry_beta.first]);
249  prod = prod * nf_x_gamma_prime[entry_gamma.first];
250  prod = prod * Mon[entry_gamma.first];
251  sum += prod;
252  }
253  }
254  IndexPairs pairs;
255  BaseRepresentation<Number> baseRepr(mBase, sum);
256  if(!baseRepr.is_zero()) {
257  pairs = indexPairs(m);
258  }
259  mTable[m] = {baseRepr, pairs};
260  }
261  }
262 
263  // ---- step 2 ----
264  // construct the matrices expressing multiplication by a variable (see step 2)
265 
266  // ---- step 3 ----
267  // find the normal forms of all other elements in Tab(Mon)
268  // Tab(Mon) = set of products of elements from Mon
269  std::list<Monomial> tabmon;
270  for(const auto& m1 : Mon) {
271  for(const auto& m2 : Mon) {
272  Monomial prod = m1 * m2;
273  if(std::find(tabmon.begin(), tabmon.end(), prod) == tabmon.end()) {
274  tabmon.push_back(prod);
275  }
276  }
277  }
278  CARL_LOG_TRACE("carl.thom.tarski", "tabmon = " << tabmon);
279  for(const auto& m : tabmon) {
280  if(!this->contains(m)) {
281  // we do not have the normal form of m yet
282  CARL_LOG_TRACE("carl.thom.tarski.table", "still to compute: normal form for " << m);
283 
284  // make it easy here and use groebner reduce
286 
287  IndexPairs pairs;
288  BaseRepresentation<Number> baseRepr(mBase, nf_m);
289  if(!baseRepr.is_zero()) {
290  pairs = indexPairs(m);
291  }
292  mTable[m] = {baseRepr, pairs};
293  }
294  }
295  }
296 };
297 
298 template<typename C>
299 std::ostream& operator<<(std::ostream& o, const MultiplicationTable<C>& table) {
300  o << "Base = " << table.mBase << std::endl;
301  o << "Length = " << table.mTable.size() << std::endl;
302  for (const auto& entry: table.mTable) {
303  o << entry.first << "\t" << entry.second.br << "\t" << entry.second.pairs << std::endl;
304  }
305  return o;
306 }
307 
308 }
#define CARL_LOG_FUNC(channel, args)
Definition: carl-logging.h:46
#define CARL_LOG_TRACE(channel, msg)
Definition: carl-logging.h:44
#define CARL_LOG_ASSERT(channel, condition, msg)
Definition: carl-logging.h:47
carl is the main namespace for the library.
bool try_divide(const Term< Coeff > &t, const Coeff &c, Term< Coeff > &res)
Definition: Division.h:28
std::uint64_t uint
Definition: numbers.h:16
std::ostream & operator<<(std::ostream &os, const BasicConstraint< Poly > &c)
Prints the given constraint on the given stream.
bool is_zero(const Interval< Number > &i)
Check if this interval is a point-interval containing 0.
Definition: Interval.h:1453
A Variable represents an algebraic variable that can be used throughout carl.
Definition: Variable.h:85
MultivariatePolynomial & strip_lterm()
Drops the leading term.
Represents a single term, that is a numeric coefficient and a monomial.
Definition: Term.h:23
std::set< Variable > gatherVariables() const
bool hasFiniteMon() const
std::vector< Monomial > bor() const
std::vector< Monomial > cor() const
std::vector< Monomial > mon() const
const std::vector< Polynomial > & get() const
Definition: GroebnerBase.h:51
bool contains(uint i) const
Number get(uint index) const
BaseRepresentation(const std::vector< Monomial > &base, const MultivariatePolynomial< Number > &p)
std::forward_list< std::pair< uint, uint > > IndexPairs
std::unordered_map< Monomial, TableContent > mTable
MultiplicationTable(const GroebnerBase< Number > &gb)
std::unordered_map< Monomial, TableContent >::const_iterator cbegin() const
BaseRepresentation< Number > multiply(const BaseRepresentation< Number > &f, const BaseRepresentation< Number > &g) const
void init(const GroebnerBase< Number > &gb)
std::unordered_map< Monomial, TableContent >::const_iterator end() const
const TableContent & getEntry(const Monomial &mon) const
bool contains(const Monomial &m) const
std::unordered_map< Monomial, TableContent >::const_iterator cend() const
MultivariatePolynomial< Number > baseReprToPolynomial(const BaseRepresentation< Number > &baseRepr) const
std::vector< Monomial > mBase
GroebnerBase< Number > mGb
BaseRepresentation< Number > reduce(const MultivariatePolynomial< Number > &p) const
friend std::ostream & operator<<(std::ostream &o, const MultiplicationTable< C > &table)
Number trace(const BaseRepresentation< Number > &f) const
IndexPairs indexPairs(const Monomial &c) const
std::unordered_map< Monomial, TableContent >::const_iterator begin() const
const std::vector< Monomial > & getBase() const noexcept