carl  24.04
Computer ARithmetic Library
MultivariateHorner.tpp
Go to the documentation of this file.
1  /**
2  * @file MultivariateHorner.tpp
3  * @author Lukas Netz
4  *
5  */
6 
7 //#define DEBUG_HORNER
8 
9 namespace carl
10 {
11  //Constructor
12  template< typename PolynomialType, class strategy >
13  MultivariateHorner< PolynomialType, strategy>::MultivariateHorner (const PolynomialType& inPut) {
14  #ifdef DEBUG_HORNER
15  std::cout << __func__ << " (GreedyI constr) P: " << inPut << std::endl;
16  #endif
17 
18  size_t arithmeticOperationsCounter = 0;
19  if (strategy::use_arithmeticOperationsCounter)
20  {
21  //Sum of monomials
22  arithmeticOperationsCounter = inPut.nr_terms() - 1;
23 
24  typename PolynomialType::TermsType::const_iterator polynomialIt;
25  for (polynomialIt = inPut.begin(); polynomialIt != inPut.end(); polynomialIt++)
26  {
27  arithmeticOperationsCounter += polynomialIt->num_variables() - 1;
28  arithmeticOperationsCounter += polynomialIt->tdeg() - polynomialIt->num_variables();
29  if (polynomialIt->coeff() > 1) arithmeticOperationsCounter++;
30  if (polynomialIt->is_constant()) arithmeticOperationsCounter++;
31 
32  }
33  }
34 
35 
36  //static_assert(!(strategy::variableSelectionHeurisics == variableSelectionHeurisics::GREEDY_II)&&!(strategy::variableSelectionHeurisics == variableSelectionHeurisics::GREEDY_IIs), "Strategy requires Interval map");
37 
38  if (strategy::selectionType == variableSelectionHeurisics::GREEDY_II || strategy::selectionType == variableSelectionHeurisics::GREEDY_IIs){
39  auto allVariablesinPolynome = carl::variables(inPut);
40  carl::carlVariables::iterator variableIt;
41 
42  for (variableIt = allVariablesinPolynome.begin(); variableIt != allVariablesinPolynome.end(); variableIt++)
43  {
44  typename std::map<Variable, Interval<double>>::const_iterator const_iterator_map = mMap.find(*variableIt);
45  if ( const_iterator_map == mMap.end() )
46  {
47  const_iterator_map = mMap.emplace(*variableIt, Interval<double>((-1) * strategy::targetDiameter, strategy::targetDiameter)).first;
48  }
49  }
50  }
51 
52  int arithmeticOperationsReductionCounter = 0;
53 
54  //Create Horner Scheme Recursivly
55  MultivariateHorner< PolynomialType, strategy > root ( std::move(inPut), mMap, arithmeticOperationsReductionCounter );
56 
57  //Part after recursion
58  if (strategy::selectionType == variableSelectionHeurisics::GREEDY_Is || strategy::selectionType == variableSelectionHeurisics::GREEDY_IIs)
59  {
60  auto root_ptr =std::make_shared<MultivariateHorner< PolynomialType, strategy > >(root);
61  root_ptr = simplify( root_ptr );
62  root = *root_ptr;
63  }
64 
65  //Apply all changes
66  *this = root;
67 
68  if (strategy::use_arithmeticOperationsCounter)
69  {
70  std::cout <<"Total AO: "<< arithmeticOperationsCounter << " rAO: " << arithmeticOperationsReductionCounter << " inPut: " << inPut << " Output: " << root << std::endl;
71 
72  if (arithmeticOperationsReductionCounter > 0)
73  {
74  std::cout << "\n\n\n\n\n IT WORKED !!! \n\n\n\n\n" << std::endl;
75  }
76  }
77  }
78 
79 
80  //Constructor for Greedy II and Greedy I
81  template< typename PolynomialType, typename strategy >
82  MultivariateHorner< PolynomialType, strategy>::MultivariateHorner (const PolynomialType& inPut, const std::map<Variable, Interval<double>>& map) {
83  #ifdef DEBUG_HORNER
84  std::cout << __func__ << " (GreedyII constr) P: " << inPut << std::endl;
85  #endif
86 
87  //Create Horner Scheme Recursivly
88  MultivariateHorner< PolynomialType, strategy > root (std::move(inPut), true, map);
89 
90  //Part after recursion
91  if (strategy::selectionType == variableSelectionHeurisics::GREEDY_Is || strategy::selectionType == variableSelectionHeurisics::GREEDY_IIs)
92  {
93  auto root_ptr =std::make_shared<MultivariateHorner< PolynomialType, strategy > >(root);
94  root_ptr = simplify( root_ptr );
95  root = *root_ptr;
96  }
97 
98  //Apply all changes
99  *this = root;
100  }
101 
102 
103  //Constructor for Greedy I/II creates recursive Datastruckture
104  template< typename PolynomialType, typename strategy >
105  MultivariateHorner< PolynomialType, strategy>::MultivariateHorner (const PolynomialType& inPut, const std::map<Variable, Interval<double>>& map, int& counter)
106  {
107  int s = strategy::selectionType;
108 
109  carl::carlVariables::iterator variableIt;
110  carl::carlVariables::iterator selectedVariable;
111  auto allVariablesinPolynome = carl::variables(inPut);
112 
113  Interval<double> currentInterval(0);
114  CoeffType delta = constant_zero<CoeffType>::get();
115  CoeffType bestDelta = constant_zero<CoeffType>::get();
116 
117  unsigned int monomials_containingChoosenVar = 0;
118 
119  if (!allVariablesinPolynome.empty())
120  {
121  //Detecting amounts of Variables in Monomials
122  for (variableIt = allVariablesinPolynome.begin(); variableIt != allVariablesinPolynome.end(); variableIt++)
123  {
124  if (s == variableSelectionHeurisics::GREEDY_I || s == variableSelectionHeurisics::GREEDY_Is)
125  {
126  unsigned int monomialCounter = 0;
127  typename PolynomialType::TermsType::const_iterator polynomialIt;
128  for (polynomialIt = inPut.begin(); polynomialIt != inPut.end(); polynomialIt++)
129  {
130  if (polynomialIt->has(*variableIt))
131  {
132  monomialCounter++;
133  }
134  }
135 
136  //saving most promising Variable for later
137  if ( monomialCounter >= monomials_containingChoosenVar ) {
138  monomials_containingChoosenVar = monomialCounter;
139  selectedVariable = variableIt;
140  }
141  }
142 
143  if (s == variableSelectionHeurisics::GREEDY_II || s == variableSelectionHeurisics::GREEDY_IIs)
144  {
145  typename PolynomialType::TermsType::const_iterator polynomialIt;
146  CoeffType accMonomEval = constant_zero<CoeffType>::get();
147  CoeffType accMonomDivEval = constant_zero<CoeffType>::get();
148 
149  for (polynomialIt = inPut.begin(); polynomialIt != inPut.end(); polynomialIt++)
150  {
151  if (polynomialIt->has(*variableIt))
152  {
153  Term< typename PolynomialType::CoeffType > currentTerm = *polynomialIt;
154  Term< typename PolynomialType::CoeffType > currentTerm_div = *polynomialIt;
155 
156  currentTerm_div.divide(*variableIt, currentTerm_div);
157 
158  currentInterval = carl::evaluate( currentTerm_div, map );
159 
160  accMonomEval += carl::rationalize<CoeffType>(carl::evaluate( currentTerm, map ).diameter());
161  accMonomDivEval += carl::rationalize<CoeffType>(currentInterval.diameter());
162 
163  }
164  }
165  accMonomDivEval *= carl::rationalize<CoeffType>(map.find(*variableIt)->second.diameter());
166  delta = accMonomDivEval - accMonomEval;
167 
168  if (delta > bestDelta )
169  {
170  #ifdef DEBUG_HORNER
171  std::cout << "update Delta...";
172  #endif
173 
174  bestDelta = delta;
175  selectedVariable = variableIt;
176  }
177  //std::cout << *variableIt << " D: "<< delta << " BD: "<< bestDelta << "\n" << std::endl;
178  }
179  }
180 
181  //Setting the choosen Variable for the current Hornerscheme iterartion
182 
183  if ((*selectedVariable == NULL && (strategy::selectionType == variableSelectionHeurisics::GREEDY_Is || strategy::selectionType == variableSelectionHeurisics::GREEDY_I))
184  || (bestDelta == constant_zero<CoeffType>::get() && (strategy::selectionType == variableSelectionHeurisics::GREEDY_IIs || strategy::selectionType == variableSelectionHeurisics::GREEDY_II)) )
185  {
186  selectedVariable = allVariablesinPolynome.begin();
187  }
188  this->setVariable(*selectedVariable);
189 
190  #ifdef DEBUG_HORNER
191  std::cout << __func__ << " Polynome: " << inPut << std::endl;
192  std::cout << "Choosen Var: " << *selectedVariable << std::endl;
193  #endif
194 
195  typename PolynomialType::TermsType::const_iterator polynomialIt;
196  typename PolynomialType::TermType tempTerm;
197 
198  typename PolynomialType::PolyType h_independentPart;
199  typename PolynomialType::PolyType h_dependentPart;
200 
201  //Choose Terms from Polynome denpending on dependency on choosen Variable
202  for (polynomialIt = inPut.begin(); polynomialIt != inPut.end(); polynomialIt++)
203  {
204  if (polynomialIt->has(*selectedVariable))
205  {
206  //divide dependent terms by choosen Variable
207 
208  polynomialIt->divide(*selectedVariable, tempTerm);
209  counter++;
210  h_dependentPart.addTerm( tempTerm );
211  }
212  else
213  {
214  h_independentPart.addTerm( *polynomialIt );
215  }
216  }
217 
218  counter = counter - 1;
219 
220  //If Dependent Polynome contains Variables - continue with recursive Horner
221  if ( !h_dependentPart.is_number() )
222  {
223  #ifdef DEBUG_HORNER
224  std::cout << __func__ << " DEP->new Horner " << h_dependentPart << std::endl;
225  #endif
226  std::shared_ptr<MultivariateHorner<PolynomialType, strategy>> new_dependent (new MultivariateHorner< PolynomialType, strategy >(std::move(h_dependentPart), map, counter));
227  setDependent(new_dependent);
228  mConst_dependent = constant_zero<CoeffType>::get();
229  }
230 
231  //Dependent Polynome is a Constant (Number) - save to memberVar
232  else
233  {
234  removeDependent();
235  mConst_dependent = h_dependentPart.constant_part();
236  }
237 
238  //If independent Polynome contains Variables - continue with recursive Horner
239  if ( !h_independentPart.is_number() )
240  {
241  #ifdef DEBUG_HORNER
242  std::cout << __func__ << " INDEP->new Horner " << h_independentPart << std::endl;
243  #endif
244  std::shared_ptr<MultivariateHorner<PolynomialType, strategy>> new_independent ( new MultivariateHorner< PolynomialType, strategy >(std::move(h_independentPart) ,map, counter));
245  setIndependent(new_independent);
246  mConst_independent = constant_zero<CoeffType>::get();
247  }
248  //Independent Polynome is a Constant (Number) - save to memberVar
249  else
250  {
251  removeIndepenent();
252  mConst_independent = h_independentPart.constant_part();
253  }
254  }
255 
256  //If there are no Variables in the polynome
257  else
258  {
259  #ifdef DEBUG_HORNER
260  std::cout << __func__ << " [CONSTANT TERM w/o Variables] " << inPut << std::endl;
261  #endif
262  removeIndepenent();
263  removeDependent();
264  mConst_independent = inPut.constant_part();
265  this->setVariable( Variable::NO_VARIABLE );
266  }
267  }
268 
269 
270 
271 /**
272  * Streaming operator for multivariate HornerSchemes.
273  * @param os Output stream.
274  * @param rhs HornerScheme.
275  * @return `os`.
276  */
277 template< typename PolynomialType, typename strategy >
278 std::ostream& operator<<(std::ostream& os,const MultivariateHorner<PolynomialType, strategy>& mvH)
279 {
280  if (mvH.getDependent() && mvH.getIndependent())
281  {
282  if (mvH.getExponent() != 1)
283  {
284  return (os << mvH.getVariable() <<"^"<< mvH.getExponent() << " * (" << *mvH.getDependent() << ") + " << *mvH.getIndependent());
285  }
286  else
287  {
288  return (os << mvH.getVariable() << " * (" << *mvH.getDependent() << ") + " << *mvH.getIndependent());
289  }
290 
291  }
292  else if (mvH.getDependent() && !mvH.getIndependent())
293  {
294  if (mvH.getIndepConstant() == 0)
295  {
296  if (mvH.getExponent() != 1)
297  {
298  return (os << mvH.getVariable() <<"^"<< mvH.getExponent() << " * (" << *mvH.getDependent() << ")" );
299  }
300  else
301  {
302  return (os << mvH.getVariable() << " * (" << *mvH.getDependent() << ")" );
303  }
304  }
305  else
306  {
307  if (mvH.getExponent() != 1)
308  {
309  return (os << mvH.getVariable() <<"^"<< mvH.getExponent() << " * (" << *mvH.getDependent() << ") + " << mvH.getIndepConstant());
310  }
311  else
312  {
313  return (os << mvH.getVariable() << " * (" << *mvH.getDependent() << ") + " << mvH.getIndepConstant());
314  }
315  }
316  }
317  else if (!mvH.getDependent() && mvH.getIndependent())
318  {
319  if (mvH.getDepConstant() == 1)
320  {
321  if (mvH.getExponent() != 1)
322  {
323  return (os << mvH.getVariable() <<"^"<< mvH.getExponent() << " + " << *mvH.getIndependent() );
324  }
325  else
326  {
327  return (os << mvH.getVariable() << " + " << *mvH.getIndependent() );
328  }
329  }
330  else
331  {
332  if (mvH.getExponent() != 1)
333  {
334  return (os << mvH.getDepConstant() << mvH.getVariable() <<"^"<< mvH.getExponent() << " + " << *mvH.getIndependent() );
335  }
336  else
337  {
338  return (os << mvH.getDepConstant() << mvH.getVariable() <<" + " << *mvH.getIndependent() );
339  }
340  }
341  }
342  else //if (mvH.getDependent() == NULL && mvH.getIndependent() == NULL)
343  {
344  if (mvH.getVariable() == Variable::NO_VARIABLE)
345  {
346  return (os << mvH.getIndepConstant());
347  }
348 
349  else if (mvH.getIndepConstant() == 0)
350  {
351  if (mvH.getDepConstant() == 1)
352  {
353  if (mvH.getExponent() != 1)
354  {
355  return (os << mvH.getVariable() <<"^"<< mvH.getExponent() );
356  }
357  else
358  {
359  return (os << mvH.getVariable());
360  }
361 
362  }
363  else
364  {
365  if (mvH.getExponent() != 1)
366  {
367  return (os << mvH.getDepConstant() << mvH.getVariable() <<"^"<< mvH.getExponent());
368  }
369  else
370  {
371  return (os << mvH.getDepConstant() << mvH.getVariable());
372  }
373  }
374  }
375  else
376  {
377  if (mvH.getExponent() != 1)
378  {
379  return (os << mvH.getDepConstant() << mvH.getVariable() <<"^"<< mvH.getExponent() << " + " << mvH.getIndepConstant());
380  }
381  else
382  {
383  return (os << mvH.getDepConstant() << mvH.getVariable() <<" + " << mvH.getIndepConstant());
384  }
385 
386  }
387  }
388 }
389 
390 template<typename PolynomialType, typename strategy>
391 std::shared_ptr<MultivariateHorner<PolynomialType, strategy>> simplify( std::shared_ptr<MultivariateHorner<PolynomialType, strategy>> mvH)
392 {
393 
394  #ifdef DEBUG_HORNER
395  std::cout << __func__ << " Polynome: " << *mvH << std::endl;
396  #endif
397 
398  if (mvH->getDependent() && (mvH->getDependent()->getDependent() || mvH->getDependent()->getDepConstant() != 0) && !mvH->getDependent()->getIndependent() && mvH->getDependent()->getIndepConstant() == 0 )
399  {
400 
401  if (mvH->getVariable() == mvH->getDependent()->getVariable())
402  {
403  mvH->setExponent (mvH->getExponent() + mvH->getDependent()->getExponent()) ;
404 
405  if (mvH->getDependent()->getDependent())
406  {
407  mvH->setDependent( simplify( mvH->getDependent()->getDependent()) );
408  }
409  else if (mvH->getDependent()->getDepConstant() != 0)
410  {
411  mvH->setDepConstant(mvH->getDependent()->getDepConstant() );
412  mvH->removeDependent();
413  }
414 
415  if (mvH->getIndependent())
416  {
417  mvH->setIndependent( simplify( mvH->getIndependent() ));
418  }
419 
420  return ( simplify(mvH));
421  }
422  }
423 
424  else if (!mvH->getDependent() && mvH->getIndependent())
425  {
426  mvH->setIndependent(simplify ( mvH->getIndependent() ));
427  mvH->removeDependent();
428  return mvH;
429  }
430 
431  else if (mvH->getDependent() && !mvH->getIndependent() )
432  {
433  mvH->setDependent( simplify ( mvH->getDependent()));
434  mvH->removeIndepenent();
435  return mvH;
436  }
437 
438  else if (mvH->getDependent() && mvH->getIndependent() )
439  {
440  mvH->setDependent( simplify( mvH->getDependent()));
441  mvH->setIndependent( simplify ( mvH->getIndependent()));
442  return mvH;
443  }
444 
445  return(mvH);
446 }
447 
448 }//namespace carl