carl  24.04
Computer ARithmetic Library
StringParser.h
Go to the documentation of this file.
1 /**
2  * @file: stringparser.h
3  * @author: Sebastian Junges
4  *
5  * @since March 17, 2014
6  */
7 
8 
9 #pragma once
10 
11 #include <cassert>
12 #include <exception>
13 #include <iostream>
14 #include <vector>
15 
16 #include <boost/lexical_cast.hpp>
17 #include <boost/algorithm/string.hpp>
19 
23 
25 
26 
27 namespace carl::io
28 {
29 
30 
31  //enum class CoeffType { Integer, Rational };
32  //enum class NumbLib { CLN, GMPPlusPlus };
33  class InvalidInputStringException : public std::runtime_error
34  {
35  using cstring = const char*;
36 
37  /// Substring where the problem is.
38  const std::string mSubstring;
39  /// Error message
40  std::string mErrorString;
41  public:
42  InvalidInputStringException(const std::string& msg, std::string substring, const std::string& inputString = ""):
43  std::runtime_error(msg), mSubstring(std::move(substring))
44  {
45  setInputString(inputString);
46  }
47 
48  void setInputString(const std::string& inputString)
49  {
50  std::stringstream strstr;
51  strstr << std::runtime_error::what() << " at " << mSubstring << " in " << inputString;
52  mErrorString = strstr.str();
53  }
54 
55 #ifdef __VS
56  virtual cstring what() const override
57 #else
58  virtual cstring what() const noexcept override
59 #endif
60  {
61  return mErrorString.c_str();
62  }
63  };
64 
65 
66 
67 
68 
70  {
71  protected:
74  bool mSumOfTermsForm = true;
75  std::map<std::string, Variable> mVars;
76 
77  public:
79  mSingleSymbVariables(false),
81  mSumOfTermsForm(true),
82  mVars()
83  {
84  }
85 
86  const std::map<std::string, Variable>& variables() const {
87  return mVars;
88  }
89 
90  void setVariables(std::list<std::string> variables)
91  {
92  mSingleSymbVariables = true;
93  variables.sort();
94  variables.unique();
95  for(const std::string& v : variables)
96  {
97  if(v.length() > 1)
98  {
99  mSingleSymbVariables = false;
101  }
102  mVars.emplace(v, fresh_real_variable(v));
103  }
104  }
105 
107  {
109  {
111  return true;
112  }
113  else
114  {
115  return false;
116  }
117  }
118 
119  /**
120  * In SumOfTermsForm, input strings are expected to be of the form "c_1 * m_1 + ... + c_n * m_n",
121  * where c_i are coefficients and m_i are monomials.
122  * @param to value to set
123  * @return
124  */
125  void setSumOfTermsForm(bool to)
126  {
127  CARL_LOG_ASSERT("carl.stringparser", to, "Extended parser not supported");
128  mSumOfTermsForm = to;
129  }
130 
131  template<typename C, typename O = typename MultivariatePolynomial<C>::OrderedBy, typename P = typename MultivariatePolynomial<C>::Policy>
133  {
134  std::vector<std::string> nomAndDenom;
135  boost::split(nomAndDenom, inputString, boost::is_any_of("/"));
136  assert(!nomAndDenom.empty());
137  if(nomAndDenom.size() > 2)
138  {
139  throw InvalidInputStringException("Multiple divisions, unclear which is division", inputString , inputString);
140  }
141  else if(nomAndDenom.size() == 2)
142  {
143  auto nom = parseMultivariatePolynomial<C>(nomAndDenom.front());
144  auto denom = parseMultivariatePolynomial<C>(nomAndDenom.back());
145  if(denom.is_zero())
146  {
147  throw InvalidInputStringException("Denominator is zero", nomAndDenom.back() , inputString);
148  }
149  return {nom, denom};
150  }
151  else
152  {
153  assert(nomAndDenom.size() == 1);
154  auto pol = parseMultivariatePolynomial<C>(nomAndDenom.front());
155  return {pol};
156  }
157  }
158 
159  template<typename C, typename O = typename MultivariatePolynomial<C>::OrderedBy, typename P = typename MultivariatePolynomial<C>::Policy>
160  MultivariatePolynomial<C, O, P> parseMultivariatePolynomial(const std::string& inputString) const
161  {
163  std::vector<std::string> termStrings;
164  if(mSumOfTermsForm)
165  {
166  boost::split(termStrings,inputString,boost::is_any_of("+"));
167 
168  for(std::string& tStr : termStrings)
169  {
170  boost::trim(tStr);
171  try
172  {
173  result += parseTerm<C>(tStr);
174  }
175  catch(InvalidInputStringException& e)
176  {
177  e.setInputString(inputString);
178  throw;
179  }
180  }
181  }
182  else
183  {
185  }
186  return result;
187  }
188 
189  template<typename C>
190  Term<C> parseTerm(const std::string& inputStr) const
191  {
192  C coeff = 1;
193  std::vector<std::pair<Variable, exponent>> varExpPairs;
195  {
196  std::vector<std::string> varExpPairStrings;
197  boost::split(varExpPairStrings, inputStr, boost::is_any_of("*"));
198 
199 
200  for(const std::string& veStr : varExpPairStrings)
201  {
202  std::vector<std::string> varAndExp;
203  boost::split(varAndExp, veStr, boost::is_any_of("^"));
204  if(varAndExp.size() > 2)
205  {
206  throw InvalidInputStringException("Two carats in one variable-exponent pair", veStr, "");
207  }
208 
209  if(varAndExp.size() == 1)
210  {
211  auto it = mVars.find(veStr);
212  if(it != mVars.end())
213  {
214  varExpPairs.emplace_back(it->second, 1);
215  }
216  else
217  {
218  coeff *= constructCoefficient<C>(veStr);
219  }
220  }
221  else
222  {
223  assert(varAndExp.size() == 2);
224  auto it = mVars.find(varAndExp.front());
225  if(it != mVars.end())
226  {
227  try
228  {
229  unsigned exp = boost::lexical_cast<unsigned>(varAndExp.back());
230  varExpPairs.emplace_back(it->second, exp);
231  }
232  catch(const boost::bad_lexical_cast&)
233  {
234  throw InvalidInputStringException("Exponent is not a number", veStr);
235  }
236  }
237  else
238  {
239  throw InvalidInputStringException("Unknown variable", varAndExp.front());
240  }
241  }
242  }
243  }
244  else
245  {
246  CARL_LOG_ASSERT("carl.stringparser", mSingleSymbVariables, "The implicit mode can only be set with single symbol variables");
247  }
248 
249  std::sort(varExpPairs.begin(), varExpPairs.end(), [](const std::pair<Variable, exponent>& p1, const std::pair<Variable, exponent>& p2){ return p1.first < p2.first; });
250  size_t nrVariables = varExpPairs.size();
251  std::unique(varExpPairs.begin(), varExpPairs.end());
252  if(nrVariables != varExpPairs.size())
253  {
254  throw InvalidInputStringException("Variable occurs twice", inputStr);
255  }
256  if(varExpPairs.empty())
257  {
258  return Term<C>(coeff);
259  }
260  else
261  {
262  std::shared_ptr<const Monomial> result = createMonomial( std::move(varExpPairs) );
263  return Term<C>(coeff, result);
264  }
265 
266  }
267 
268  protected:
269  template<typename C>
270  C constructCoefficient(const std::string& inputString) const
271  {
272  std::string inputStringCopy = inputString;
273  assert(!inputStringCopy.empty());
274  if( inputStringCopy[0] == '(' )
275  {
276  assert(inputStringCopy.back() == ')');
277  inputStringCopy = inputStringCopy.substr( 1, inputStringCopy.size()-2 );
278  }
279  try
280  {
281  return parse<C>(inputStringCopy);
282  }
283  catch(std::exception&)
284  {
285  throw InvalidInputStringException("Could not build coefficient", inputStringCopy);
286  }
287 
288  }
289 
290  };
291 
292 }
A small wrapper that configures logging for carl.
#define CARL_LOG_ASSERT(channel, condition, msg)
Definition: carl-logging.h:47
#define CARL_LOG_NOTIMPLEMENTED()
Definition: carl-logging.h:48
Monomial::Arg createMonomial(T &&... t)
Definition: MonomialPool.h:168
Interval< Number > exp(const Interval< Number > &i)
Definition: Exponential.h:10
Variable fresh_real_variable() noexcept
Definition: VariablePool.h:198
The general-purpose multivariate polynomial class.
Represents a single term, that is a numeric coefficient and a monomial.
Definition: Term.h:23
std::string mErrorString
Error message.
Definition: StringParser.h:40
virtual cstring what() const noexcept override
Definition: StringParser.h:58
const std::string mSubstring
Substring where the problem is.
Definition: StringParser.h:38
InvalidInputStringException(const std::string &msg, std::string substring, const std::string &inputString="")
Definition: StringParser.h:42
void setInputString(const std::string &inputString)
Definition: StringParser.h:48
std::map< std::string, Variable > mVars
Definition: StringParser.h:75
void setVariables(std::list< std::string > variables)
Definition: StringParser.h:90
void setSumOfTermsForm(bool to)
In SumOfTermsForm, input strings are expected to be of the form "c_1 * m_1 + ... + c_n * m_n",...
Definition: StringParser.h:125
const std::map< std::string, Variable > & variables() const
Definition: StringParser.h:86
MultivariatePolynomial< C, O, P > parseMultivariatePolynomial(const std::string &inputString) const
Definition: StringParser.h:160
C constructCoefficient(const std::string &inputString) const
Definition: StringParser.h:270
bool setImplicitMultiplicationMode(bool to)
Definition: StringParser.h:106
Term< C > parseTerm(const std::string &inputStr) const
Definition: StringParser.h:190
RationalFunction< MultivariatePolynomial< C, O, P > > parseRationalFunction(const std::string &inputString) const
Definition: StringParser.h:132