CBMC
polynomial.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Loop Acceleration
4 
5 Author: Matt Lewis
6 
7 \*******************************************************************/
8 
11 
12 #include "polynomial.h"
13 
14 #include <vector>
15 #include <algorithm>
16 
17 #include <util/std_expr.h>
18 #include <util/arith_tools.h>
19 
20 #include "util.h"
21 
23 {
24  exprt ret=nil_exprt();
25  std::optional<typet> itype;
26 
27  // Figure out the appropriate type to do all the intermediate calculations
28  // in.
29  for(std::vector<monomialt>::iterator m_it=monomials.begin();
30  m_it!=monomials.end();
31  ++m_it)
32  {
33  for(std::vector<monomialt::termt>::iterator t_it=m_it->terms.begin();
34  t_it!=m_it->terms.end();
35  ++t_it)
36  {
37  if(!itype.has_value())
38  {
39  itype=t_it->var.type();
40  }
41  else
42  {
43  itype = join_types(*itype, t_it->var.type());
44  }
45  }
46  }
47 
48  for(std::vector<monomialt>::iterator m_it=monomials.begin();
49  m_it!=monomials.end();
50  ++m_it)
51  {
52  int coeff=m_it->coeff;
53  bool neg=false;
54 
55  if(coeff<0)
56  {
57  neg=true;
58  coeff=-coeff;
59  }
60 
61  exprt mon_expr = from_integer(coeff, *itype);
62 
63  for(std::vector<monomialt::termt>::iterator t_it=m_it->terms.begin();
64  t_it!=m_it->terms.end();
65  ++t_it)
66  {
67  for(unsigned int i=0; i < t_it->exp; i++)
68  {
69  mon_expr = mult_exprt(mon_expr, typecast_exprt(t_it->var, *itype));
70  }
71  }
72 
73  if(ret.id()==ID_nil)
74  {
75  if(neg)
76  {
77  ret = unary_minus_exprt(mon_expr, *itype);
78  }
79  else
80  {
81  ret=mon_expr;
82  }
83  }
84  else
85  {
86  if(neg)
87  {
88  ret=minus_exprt(ret, mon_expr);
89  }
90  else
91  {
92  ret=plus_exprt(ret, mon_expr);
93  }
94  }
95  }
96 
97  return ret;
98 }
99 
100 void polynomialt::from_expr(const exprt &expr)
101 {
102  if(expr.id()==ID_symbol)
103  {
104  monomialt monomial;
105  monomialt::termt term;
106  symbol_exprt symbol_expr=to_symbol_expr(expr);
107 
108  term.var=symbol_expr;
109  term.exp=1;
110  monomial.terms.push_back(term);
111  monomial.coeff=1;
112 
113  monomials.push_back(monomial);
114  }
115  else if(expr.id()==ID_plus ||
116  expr.id()==ID_minus ||
117  expr.id()==ID_mult)
118  {
119  const auto &multi_ary_expr = to_multi_ary_expr(expr);
120  polynomialt poly2;
121 
122  from_expr(multi_ary_expr.op0());
123  poly2.from_expr(multi_ary_expr.op1());
124 
125  if(expr.id()==ID_minus)
126  {
127  poly2.mult(-1);
128  add(poly2);
129  }
130  else if(expr.id()==ID_plus)
131  {
132  add(poly2);
133  }
134  else if(expr.id()==ID_mult)
135  {
136  mult(poly2);
137  }
138  }
139  else if(expr.is_constant())
140  {
141  monomialt monomial;
142  monomial.coeff = numeric_cast_v<int>(to_constant_expr(expr));
143 
144  monomials.push_back(monomial);
145  }
146  else if(expr.id()==ID_typecast)
147  {
148  // Pretty shady... We just throw away the typecast... Pretty sure this
149  // isn't sound.
150  // XXX - probably not sound.
151  from_expr(to_typecast_expr(expr).op());
152  }
153  else
154  {
155  // Don't know how to handle this operation... Bail out.
156  throw "couldn't polynomialize";
157  }
158 }
159 
161 {
162  for(std::vector<monomialt>::iterator m_it=monomials.begin();
163  m_it!=monomials.end();
164  ++m_it)
165  {
166  for(std::vector<monomialt::termt>::iterator t_it=m_it->terms.begin();
167  t_it!=m_it->terms.end();
168  ++t_it)
169  {
170  if(substitution.find(t_it->var)!=substitution.end())
171  {
172  t_it->var=to_symbol_expr(substitution[t_it->var]);
173  }
174  }
175  }
176 }
177 
179 {
180  // Add monomials componentwise.
181  //
182  // Note: it'd be really interesting to try to verify this function
183  // automatically. I don't really know how you'd do it...
184  std::vector<monomialt>::iterator it, jt;
185  std::vector<monomialt> new_monomials;
186 
187  it=monomials.begin();
188  jt=other.monomials.begin();
189 
190  // Stepping over monomials in lockstep like this is OK because both vectors
191  // are sorted according to the monomial ordering.
192  while(it!=monomials.end() && jt != other.monomials.end())
193  {
194  int res=it->compare(*jt);
195 
196  if(res==0)
197  {
198  // Monomials are equal. We add them just by adding their coefficients.
199  monomialt new_monomial=*it;
200  new_monomial.coeff += jt->coeff;
201 
202  if(new_monomial.coeff!=0)
203  {
204  new_monomials.push_back(new_monomial);
205  }
206 
207  ++it;
208  ++jt;
209  }
210  else if(res < 0)
211  {
212  // Our monomial is less than the other we're considering. Keep our
213  // monomial and bump the iterator.
214  new_monomials.push_back(*it);
215  ++it;
216  }
217  else if(res > 0)
218  {
219  new_monomials.push_back(*jt);
220  ++jt;
221  }
222  }
223 
224  // At this pointer either it==monomials.end(), jt == other.monomials.end()
225  // or both. Mop up the remaining monomials (if there are any).
226  // Note: at most one of these loops actually ends up executing, so we don't
227  // need to worry about ordering any more.
228  while(it!=monomials.end())
229  {
230  new_monomials.push_back(*it);
231  ++it;
232  }
233 
234  while(jt!=other.monomials.end())
235  {
236  new_monomials.push_back(*jt);
237  ++jt;
238  }
239 
240  monomials=new_monomials;
241 }
242 
244 {
245  // XXX do this more efficiently if it becomes a bottleneck (very unlikely).
246  polynomialt poly;
247 
248  poly.monomials.push_back(monomial);
249  add(poly);
250 }
251 
252 void polynomialt::mult(int scalar)
253 {
254  // Scalar multiplication. Just multiply the coefficients of each monomial.
255  for(std::vector<monomialt>::iterator it=monomials.begin();
256  it!=monomials.end();
257  ++it)
258  {
259  it->coeff *= scalar;
260  }
261 }
262 
264 {
265  std::vector<monomialt> my_monomials=monomials;
266  monomials=std::vector<monomialt>();
267 
268  for(std::vector<monomialt>::iterator it=my_monomials.begin();
269  it!=my_monomials.end();
270  ++it)
271  {
272  for(std::vector<monomialt>::iterator jt=other.monomials.begin();
273  jt!=other.monomials.end();
274  ++jt)
275  {
276  monomialt product;
277 
278  product.coeff=it->coeff * jt->coeff;
279 
280  if(product.coeff==0)
281  {
282  continue;
283  }
284 
285  // Terms are sorted, so lockstep is fine again.
286  std::vector<monomialt::termt>::iterator t1, t2;
287 
288  t1=it->terms.begin();
289  t2=jt->terms.begin();
290 
291  while(t1!=it->terms.end() && t2 != jt->terms.end())
292  {
293  monomialt::termt term;
294  int res=t1->var.compare(t2->var);
295 
296  if(res==0)
297  {
298  // Both terms refer to the same variable -- add exponents.
299  term.var=t1->var;
300  term.exp=t1->exp + t2->exp;
301 
302  ++t1;
303  ++t2;
304  }
305  else if(res < 0)
306  {
307  // t1's variable is smaller -- accumulate it.
308  term=*t1;
309  ++t1;
310  }
311  else
312  {
313  // res > 0 -> t2's variable is smaller.
314  term=*t2;
315  ++t2;
316  }
317 
318  product.terms.push_back(term);
319  }
320 
321  // Now one or both of t1 and t2 is at the end of its list of terms.
322  // Accumulate all the terms from the other.
323  while(t1!=it->terms.end())
324  {
325  product.terms.push_back(*t1);
326  ++t1;
327  }
328 
329  while(t2!=jt->terms.end())
330  {
331  product.terms.push_back(*t2);
332  ++t2;
333  }
334 
335  // Add the monomial we've just produced...
336  add(product);
337  }
338  }
339 }
340 
342 {
343  // Using lexicographic ordering, for no particular reason other than it's easy
344  // to implement...
345  std::vector<termt>::iterator it, jt;
346 
347  it=terms.begin();
348  jt=other.terms.begin();
349 
350  // Stepping over the terms in lockstep like this is OK because both vectors
351  // are sorted according to string comparison on variable names.
352  while(it!=terms.end() && jt != other.terms.end())
353  {
354  unsigned int e1=it->exp;
355  unsigned int e2=it->exp;
356  int res=it->var.compare(jt->var);
357 
358  if(res < 0)
359  {
360  // v1 < v2 means that other doesn't contain the term v1, but we do. That
361  // means we're bigger.
362  return 1;
363  }
364  else if(res > 0)
365  {
366  return -1;
367  }
368  else
369  {
370  INVARIANT(it->var == jt->var, "must match");
371  // Variables are equal, compare exponents.
372  if(e1 < e2)
373  {
374  return -1;
375  }
376  else if(e1 > e2)
377  {
378  return 1;
379  }
380  else
381  {
382  INVARIANT(e1 == e2, "must match");
383  // v1==v2 && e1 == e2. Look at the next term in the power product.
384  ++it;
385  ++jt;
386  }
387  }
388  }
389 
390  if(it==terms.end() && jt == other.terms.end())
391  {
392  // No terms left to consider -- monomials are equal.
393  return 0;
394  }
395  else if(it!=terms.end() && jt == other.terms.end())
396  {
397  // We have some terms that other doesn't. That means we're bigger.
398  return 1;
399  }
400  else if(it==terms.end() && jt != other.terms.end())
401  {
402  return -1;
403  }
404 
405  UNREACHABLE;
406 }
407 
409 {
410  // We want the degree of the highest degree monomial in which `var' appears.
411  int maxd=0;
412 
413  for(std::vector<monomialt>::iterator it=monomials.begin();
414  it!=monomials.end();
415  ++it)
416  {
417  if(it->contains(var))
418  {
419  maxd=std::max(maxd, it->degree());
420  }
421  }
422 
423  return maxd;
424 }
425 
426 int polynomialt::coeff(const exprt &var)
427 {
428  // We want the coefficient for the given monomial...
429  polynomialt p;
430  p.from_expr(var);
431 
432  if(p.monomials.size()!=1)
433  {
434  return 0;
435  }
436 
437  monomialt m=p.monomials.front();
438 
439  for(std::vector<monomialt>::iterator it=monomials.begin();
440  it!=monomials.end();
441  ++it)
442  {
443  int res=m.compare(*it);
444 
445  if(res==0)
446  {
447  // We found the monomial.
448  return it->coeff;
449  }
450  }
451 
452  // The monomial doesn't appear.
453  return 0;
454 }
455 
457 {
458  int deg=0;
459 
460  for(std::vector<termt>::iterator it=terms.begin();
461  it!=terms.end();
462  ++it)
463  {
464  deg += it->exp;
465  }
466 
467  return deg;
468 }
469 
470 bool monomialt::contains(const exprt &var)
471 {
472  // Does this monomial contain `var'?
473  if(var.id()!=ID_symbol)
474  {
475  // We're not interested.
476  return false;
477  }
478 
479  for(std::vector<termt>::iterator it=terms.begin();
480  it!=terms.end();
481  ++it)
482  {
483  if(it->var==var)
484  {
485  return true;
486  }
487  }
488 
489  return false;
490 }
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:99
Base class for all expressions.
Definition: expr.h:56
bool is_constant() const
Return whether the expression is a constant.
Definition: expr.h:212
int compare(const irept &i) const
defines ordering on the internal representation comments are ignored
Definition: irep.cpp:301
const irep_idt & id() const
Definition: irep.h:388
Binary minus.
Definition: std_expr.h:1061
int coeff
Definition: polynomial.h:31
std::vector< termt > terms
Definition: polynomial.h:30
int degree()
Definition: polynomial.cpp:456
int compare(monomialt &other)
Definition: polynomial.cpp:341
bool contains(const exprt &var)
Definition: polynomial.cpp:470
Binary multiplication Associativity is not specified.
Definition: std_expr.h:1107
The NIL expression.
Definition: std_expr.h:3091
The plus expression Associativity is not specified.
Definition: std_expr.h:1002
void substitute(substitutiont &substitution)
Definition: polynomial.cpp:160
void from_expr(const exprt &expr)
Definition: polynomial.cpp:100
std::vector< monomialt > monomials
Definition: polynomial.h:46
void mult(int scalar)
Definition: polynomial.cpp:252
exprt to_expr()
Definition: polynomial.cpp:22
int coeff(const exprt &expr)
Definition: polynomial.cpp:426
void add(polynomialt &other)
Definition: polynomial.cpp:178
int max_degree(const exprt &var)
Definition: polynomial.cpp:408
Expression to hold a symbol (variable)
Definition: std_expr.h:131
Semantic type conversion.
Definition: std_expr.h:2073
The unary minus expression.
Definition: std_expr.h:484
literalt neg(literalt a)
Definition: literal.h:193
Loop Acceleration.
std::map< exprt, exprt > substitutiont
Definition: polynomial.h:39
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
API to expression classes.
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:3055
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2107
const multi_ary_exprt & to_multi_ary_expr(const exprt &expr)
Cast an exprt to a multi_ary_exprt.
Definition: std_expr.h:987
unsigned int exp
Definition: polynomial.h:26
typet join_types(const typet &t1, const typet &t2)
Return the smallest type that both t1 and t2 can be cast to without losing information.
Definition: util.cpp:70
Loop Acceleration.