1 #ifndef _ScatterDraw_Equation_h_
2 #define _ScatterDraw_Equation_h_
3
4 #include <plugin/Eigen/Eigen.h>
5
6 namespace Upp {
7
8 #define FormatCoeff(id, numDigits) (IsNull(numDigits) ? (String("C") + FormatInt(id)) : FormatDoubleFix(coeff[id], numDigits))
9
10 class ExplicitEquation : public DataSource {
11 public:
ExplicitEquation()12 ExplicitEquation() {isExplicit = true;}
13
14 virtual void SetDegree(int num) = 0;
15 enum FitError {
16 NoError = 1,
17 InadequateDataSource = -1,
18 SmallDataSource = -2,
19 ImproperInputParameters = -3,
20 TooManyFunctionEvaluation = -4
21 };
22 virtual FitError Fit(DataSource &series, double &r2);
Fit(DataSource & series)23 FitError Fit(DataSource &series) {double dummy; return Fit(series, dummy);}
24 virtual void GuessCoeff(DataSource &series) = 0;
25
26 virtual double f(double ) = 0;
f(double,double)27 virtual double f(double , double ) {NEVER(); return Null;}
f(Vector<double>)28 virtual double f(Vector <double> ) {NEVER(); return Null;}
x(int64)29 virtual double x(int64 ) {NEVER(); return Null;}
y(int64)30 virtual double y(int64 ) {NEVER(); return Null;}
31 virtual String GetName() = 0;
GetFullName()32 virtual String GetFullName() {return GetName();}
33 virtual String GetEquation(int numDigits = 3) = 0;
GetCount()34 virtual inline int64 GetCount() const {return coeff.GetCount() > 0 ? 0 : int64(Null);}
35
SetMaxFitFunctionEvaluations(int n)36 void SetMaxFitFunctionEvaluations(int n){maxFitFunctionEvaluations = n;}
GetMaxFitFunctionEvaluations()37 int GetMaxFitFunctionEvaluations() {return maxFitFunctionEvaluations;}
38
39 friend struct Equation_functor;
40
GetCoeff()41 const Vector<double> &GetCoeff() {return coeff;}
GetCoeff(int i)42 double GetCoeff(int i) {return coeff[i];}
43
44 template<class T>
Register(const String & name)45 static void Register(const String& name) {
46 classMap().FindAdd(name, __Create<T>);
47 }
Unregister(const String & name)48 static void Unregister(const String& name) {
49 int i = NameIndex(name);
50 ASSERT(i >= 0);
51 classMap().Remove(i);
52 }
NameIndex(const String & name)53 static int NameIndex(const String& name) {return classMap().Find(name);}
GetEquationCount()54 static int GetEquationCount() {return classMap().GetCount();}
Create(int i)55 static ExplicitEquation* Create(int i) {return classMap()[i]();}
56
GetNumCoeff(int)57 int GetNumCoeff(int ) {return coeff.GetCount();}
58
59 ExplicitEquation &operator=(ExplicitEquation &other) {
60 if (this != &other) {
61 degree = other.degree;
62 coeff = clone(other.coeff);
63 }
64 return *this;
65 }
66 double R2Y(DataSource &series, double mean = Null);
67
68 protected:
69 Vector<double> coeff;
70 int degree;
71 static int maxFitFunctionEvaluations;
72
73 void SetNumCoeff(int num);
SetCoeff(const Vector<double> & c)74 void SetCoeff(const Vector<double>& c) {coeff = clone(c);}
SetCoeff(double c0,double c1,double c2)75 void SetCoeff(double c0, double c1, double c2) {coeff.Clear(); coeff << c0 << c1 << c2;}
SetCoeff(double c0,double c1)76 void SetCoeff(double c0, double c1) {coeff.Clear(); coeff << c0 << c1;}
SetCoeff(double c0)77 void SetCoeff(double c0) {coeff.Clear(); coeff << c0;}
SetCoeffVal(int id,double c)78 void SetCoeffVal(int id, double c) {coeff[id] = c;}
79
80 typedef ExplicitEquation* (*CreateFunc)();
81 template<class T>
__Create()82 static ExplicitEquation* __Create() {return new T;}
classMap()83 static VectorMap<String, CreateFunc>& classMap() {static VectorMap<String, CreateFunc> cMap; return cMap;}
84 };
85
86 class AvgEquation : public ExplicitEquation {
87 public:
AvgEquation()88 AvgEquation() {SetCoeff(0);}
AvgEquation(double c0)89 AvgEquation(double c0) {SetCoeff(c0);}
f(double)90 double f(double ) {return coeff[0];}
GetName()91 virtual String GetName() {return t_("Average");}
92 virtual String GetEquation(int _numDigits = 3) {
93 String ret = Format("%s", FormatCoeff(0, _numDigits));
94 return ret;
95 }
SetDegree(int)96 void SetDegree(int ) {NEVER();}
GuessCoeff(DataSource & series)97 virtual void GuessCoeff(DataSource &series) {coeff[0] = series.AvgY();}
98 };
99
100 class LinearEquation : public ExplicitEquation {
101 public:
LinearEquation()102 LinearEquation() {SetCoeff(0, 0);}
LinearEquation(double c0,double c1)103 LinearEquation(double c0, double c1){SetCoeff(c0, c1);}
f(double x)104 double f(double x) {
105 return coeff[0] + x*coeff[1];
106 }
GetName()107 virtual String GetName() {return t_("Linear");}
108 virtual String GetEquation(int _numDigits = 3) {
109 String ret = Format("%s + %s*x", FormatCoeff(0, _numDigits), FormatCoeff(1, _numDigits));
110 ret.Replace("+ -", "- ");
111 return ret;
112 }
SetDegree(int)113 void SetDegree(int ) {NEVER();}
GuessCoeff(DataSource & series)114 virtual void GuessCoeff(DataSource &series) {coeff[0] = series.AvgY();}
115 };
116
117 class PolynomialEquation : public ExplicitEquation {
118 public:
PolynomialEquation()119 PolynomialEquation() {}
PolynomialEquation(const Vector<double> & c)120 PolynomialEquation(const Vector<double>& c) {SetCoeff(c);}
121 double f(double x);
GetName()122 virtual String GetName() {return t_("Polynomial");}
GetFullName()123 virtual String GetFullName() {return t_("Polynomial") + String(" n = ") + FormatInt(degree);}
124 virtual String GetEquation(int numDigits = 3);
SetDegree(int num)125 void SetDegree(int num) {degree = num; SetNumCoeff(num + 1);}
GuessCoeff(DataSource & series)126 virtual void GuessCoeff(DataSource &series) {
127 coeff[0] = series.AvgY();
128 int realDegree = degree;
129 for (degree = 2; degree < realDegree; degree++)
130 Fit(series);
131 }
132 };
133
134 class PolynomialEquation2 : public PolynomialEquation {
135 public:
PolynomialEquation2()136 PolynomialEquation2() {SetDegree(2);}
137 };
138
139 class PolynomialEquation3 : public PolynomialEquation {
140 public:
PolynomialEquation3()141 PolynomialEquation3() {SetDegree(3);}
142 };
143
144 class PolynomialEquation4 : public PolynomialEquation {
145 public:
PolynomialEquation4()146 PolynomialEquation4() {SetDegree(4);}
147 };
148
149 class PolynomialEquation5 : public PolynomialEquation {
150 public:
PolynomialEquation5()151 PolynomialEquation5() {SetDegree(5);}
152 };
153
154 class SinEquation : public ExplicitEquation {
155 public:
SinEquation()156 SinEquation() {coeff.Clear(); coeff << 0. << 0.1 << 0.1 << 0.1;}
SinEquation(double offset,double A,double w,double phi)157 SinEquation(double offset, double A, double w, double phi) {Init(offset, A, w, phi);}
Init(double offset,double A,double w,double phi)158 void Init(double offset, double A, double w, double phi) {coeff.Clear(); coeff << offset << A << w << phi;}
f(double x)159 double f(double x) {return coeff[0] + coeff[1]*sin(coeff[2]*x + coeff[3]);}
GetName()160 virtual String GetName() {return t_("Sine");}
161 virtual String GetEquation(int _numDigits = 3) {
162 String ret = Format("%s + %s*sin(%s*t + %s)", FormatCoeff(0, _numDigits), FormatCoeff(1, _numDigits)
163 , FormatCoeff(2, _numDigits), FormatCoeff(3, _numDigits));
164 ret.Replace("+ -", "- ");
165 return ret;
166 }
SetDegree(int)167 void SetDegree(int ) {NEVER();}
GuessCoeff(DataSource & series)168 virtual void GuessCoeff(DataSource &series) {
169 coeff[0] = series.AvgY();
170 coeff[1] = series.SinEstim_Amplitude(coeff[0]);
171 double frequency, phase;
172 if (series.SinEstim_FreqPhase(frequency, phase, coeff[0])) {
173 coeff[2] = frequency;
174 coeff[3] = phase;
175 }
176 }
177 };
178
179 class DampedSinEquation : public ExplicitEquation {
180 public:
DampedSinEquation()181 DampedSinEquation() {coeff.Clear(); coeff << 0. << 0.1 << 0.1 << 0.1 << 0.1;}
DampedSinEquation(double offset,double A,double lambda,double w,double phi)182 DampedSinEquation(double offset, double A, double lambda, double w, double phi) {Init(offset, A, lambda, w, phi);}
Init(double offset,double A,double lambda,double w,double phi)183 void Init(double offset, double A, double lambda, double w, double phi) {coeff.Clear(); coeff << offset << A << lambda << w << phi;}
f(double x)184 double f(double x) {return coeff[0] + coeff[1]*exp(-coeff[2]*x)*cos(coeff[3]*x + coeff[4]);}
GetName()185 virtual String GetName() {return t_("DampedSinusoidal");}
186 virtual String GetEquation(int _numDigits = 3) {
187 String ret = Format("%s + %s*e^(-%s*t)*cos(%s*t + %s)", FormatCoeff(0, _numDigits),
188 FormatCoeff(1, _numDigits), FormatCoeff(2, _numDigits), FormatCoeff(3, _numDigits), FormatCoeff(4, _numDigits));
189 ret.Replace("+ -", "- ");
190 return ret;
191 }
SetDegree(int)192 void SetDegree(int ) {NEVER();}
GuessCoeff(DataSource & series)193 virtual void GuessCoeff(DataSource &series) {
194 coeff[0] = series.AvgY();
195 coeff[2] = series.SinEstim_Amplitude(coeff[0]);
196 double frequency, phase;
197 if (series.SinEstim_FreqPhase(frequency, phase, coeff[0])) {
198 coeff[3] = frequency;
199 coeff[4] = phase;
200 }
201 }
202 };
203
204 class Sin_DampedSinEquation : public ExplicitEquation {
205 public:
Sin_DampedSinEquation()206 Sin_DampedSinEquation() {coeff.Clear(); coeff << 0. << 0.1 << 0.1 << 0.1 << 0.1 << 0.1 << 0.1 << 0.1;}
Sin_DampedSinEquation(double offset,double A1,double w1,double phi1,double A2,double lambda,double w2,double phi2)207 Sin_DampedSinEquation(double offset, double A1, double w1, double phi1, double A2,
208 double lambda, double w2, double phi2) {Init(offset, A1, w1, phi1, A2, lambda, w2, phi2);}
Init(double offset,double A1,double w1,double phi1,double A2,double lambda,double w2,double phi2)209 void Init(double offset, double A1, double w1, double phi1, double A2, double lambda,
210 double w2, double phi2) {coeff.Clear();
211 coeff << offset << A1 << w1 << phi1 << A2 << lambda << w2 << phi2;}
f(double x)212 double f(double x) {return coeff[0] + coeff[1]*cos(coeff[2]*x + coeff[3]) + coeff[4]*exp(-coeff[5]*x)*cos(coeff[6]*x + coeff[7]);}
GetName()213 virtual String GetName() {return t_("Sin_DampedSinusoidal");}
214 virtual String GetEquation(int _numDigits = 3) {
215 String ret = Format("%s + %s*cos(%s*t + %s) + %s*e^(-%s*t)*cos(%s*t + %s)",
216 FormatCoeff(0, _numDigits), FormatCoeff(1, _numDigits), FormatCoeff(2, _numDigits),
217 FormatCoeff(3, _numDigits), FormatCoeff(4, _numDigits), FormatCoeff(5, _numDigits),
218 FormatCoeff(6, _numDigits), FormatCoeff(7, _numDigits));
219 ret.Replace("+ -", "- ");
220 return ret;
221 }
SetDegree(int)222 void SetDegree(int ) {NEVER();}
GuessCoeff(DataSource & series)223 virtual void GuessCoeff(DataSource &series) {
224 coeff[0] = series.AvgY();
225 coeff[1] = series.SinEstim_Amplitude(coeff[0]);
226 double frequency, phase;
227 if (series.SinEstim_FreqPhase(frequency, phase, coeff[0])) {
228 coeff[2] = frequency;
229 coeff[3] = phase;
230 }
231 }
232 };
233
234 class FourierEquation : public ExplicitEquation {
235 public:
FourierEquation()236 FourierEquation() {}
FourierEquation(const Vector<double> & c)237 FourierEquation(const Vector<double>& c) {SetCoeff(c);}
238 double f(double x);
GetName()239 virtual String GetName() {return t_("Fourier");}
GetFullName()240 virtual String GetFullName() {return t_("Fourier") + String(" n = ") + FormatInt(degree);}
241 virtual String GetEquation(int numDigits = 3);
GuessCoeff(DataSource & series)242 virtual void GuessCoeff(DataSource &series) {coeff[0] = series.AvgY();}
SetDegree(int num)243 void SetDegree(int num) {degree = num; SetNumCoeff(2*num + 2);}
244 };
245
246 class FourierEquation1 : public FourierEquation {
247 public:
FourierEquation1()248 FourierEquation1() {SetDegree(1);}
249 };
250
251 class FourierEquation2 : public FourierEquation {
252 public:
FourierEquation2()253 FourierEquation2() {SetDegree(2);}
254 };
255
256 class FourierEquation3 : public FourierEquation {
257 public:
FourierEquation3()258 FourierEquation3() {SetDegree(3);}
259 };
260
261 class FourierEquation4 : public FourierEquation {
262 public:
FourierEquation4()263 FourierEquation4() {SetDegree(4);}
264 };
265
266 class ExponentialEquation : public ExplicitEquation {
267 public:
ExponentialEquation()268 ExponentialEquation() {SetCoeff(1, 0);}
ExponentialEquation(double c0,double c1)269 ExponentialEquation(double c0, double c1) {SetCoeff(c0, c1);}
f(double x)270 double f(double x) {return coeff[0]*exp(-x) + coeff[1];}
GetName()271 virtual String GetName() {return t_("Exponential");}
272 virtual String GetEquation(int numDigits = 3) {
273 String ret = Format("%s*e^-x + %s", FormatCoeff(0, numDigits), FormatCoeff(1, numDigits));
274 ret.Replace("+ -", "- ");
275 return ret;
276 }
GuessCoeff(DataSource &)277 virtual void GuessCoeff(DataSource &) {}
SetDegree(int)278 void SetDegree(int ) {NEVER();}
279 };
280
281 class RealExponentEquation : public ExplicitEquation {
282 public:
RealExponentEquation()283 RealExponentEquation() {SetCoeff(1, 1);}
RealExponentEquation(double a,double b)284 RealExponentEquation(double a, double b) {SetCoeff(a, b);}
f(double x)285 double f(double x) {
286 if (x < 0)
287 return Null;
288 return coeff[0]*pow(x, coeff[1]);
289 }
GetName()290 virtual String GetName() {return t_("RealExponent");}
291 virtual String GetEquation(int _numDigits = 3) {
292 String ret = Format("%s*x^%s", FormatCoeff(0, _numDigits), FormatCoeff(1, _numDigits));
293 ret.Replace("+ -", "- ");
294 return ret;
295 }
GuessCoeff(DataSource &)296 virtual void GuessCoeff(DataSource &) {}
SetDegree(int)297 void SetDegree(int ) {NEVER();}
298 };
299
300 class WeibullCumulativeEquation : public ExplicitEquation {
301 public:
WeibullCumulativeEquation()302 WeibullCumulativeEquation() {SetCoeff(1, 1);}
WeibullCumulativeEquation(double k,double lambda)303 WeibullCumulativeEquation(double k, double lambda) {ASSERT(k > 0); ASSERT(lambda > 0); SetCoeff(k, lambda);}
f(double x)304 double f(double x) {
305 if (x < 0)
306 return 0;
307 double k = coeff[0];
308 double lambda = coeff[1];
309 return 1 - exp(double(-pow(x/lambda, k)));
310 }
GetName()311 virtual String GetName() {return t_("Weibull cumulative");}
312 virtual String GetEquation(int numDigits = 3) {
313 String k = FormatCoeff(0, numDigits);
314 String lambda = FormatCoeff(1, numDigits);
315 String ret = Format("1 - e^(-((x/%s)^%s))", lambda, k);
316 ret.Replace("+ -", "- ");
317 return ret;
318 }
GuessCoeff(DataSource &)319 virtual void GuessCoeff(DataSource &) {}
SetDegree(int)320 void SetDegree(int ) {NEVER();}
321 };
322
323 class WeibullEquation : public ExplicitEquation {
324 public:
WeibullEquation()325 WeibullEquation() {SetCoeff(1, 1, 1);}
WeibullEquation(double k,double lambda,double factor)326 WeibullEquation(double k, double lambda, double factor) {ASSERT(k > 0); ASSERT(lambda > 0); SetCoeff(k, lambda, factor);}
f(double x)327 double f(double x) {
328 if (x < 0)
329 return 0;
330 double k = coeff[0];
331 double lambda = coeff[1];
332 double factor = coeff[2];
333 return factor*(k/lambda)*(pow(x/lambda, k-1))*exp(double(-pow(x/lambda, k)));
334 }
GetName()335 virtual String GetName() {return t_("Weibull");}
336 virtual String GetEquation(int numDigits = 3) {
337 String k = FormatCoeff(0, numDigits);
338 String lambda = FormatCoeff(1, numDigits);
339 String sfactor = FormatCoeff(2, numDigits);
340 String ret = Format("%s*(%s/%s)*(x/%s)^(%s-1)*e^(-((x/%s)^%s))", sfactor, k, lambda, lambda, k, lambda, k);
341 ret.Replace("+ -", "- ");
342 return ret;
343 }
GuessCoeff(DataSource &)344 virtual void GuessCoeff(DataSource &) {}
_GuessCoeff(DataSource & series)345 virtual void _GuessCoeff(DataSource &series) {
346 Vector<Pointf> cumulative = series.CumulativeY();
347 double fac = cumulative.Top().y;
348 for (int i = 0; i < cumulative.GetCount(); ++i)
349 cumulative[i].y /= fac;
350 VectorPointf data(cumulative);
351 WeibullCumulativeEquation weibullCumulative;
352 ExplicitEquation::FitError error = weibullCumulative.Fit(data);
353 if (error == ExplicitEquation::NoError) {
354 double k = weibullCumulative.GetCoeff()[0];
355 double lambda = weibullCumulative.GetCoeff()[1];
356 SetCoeff(k, lambda, 1);
357 }
358 }
Fit(DataSource & series,double & r2)359 FitError Fit(DataSource &series, double &r2) {
360 _GuessCoeff(series);
361 return ExplicitEquation::Fit(series, r2);
362 }
Fit(DataSource & series)363 FitError Fit(DataSource &series) {double dummy; return Fit(series, dummy);}
SetDegree(int)364 void SetDegree(int ) {NEVER();}
365 };
366
367 class NormalEquation : public ExplicitEquation {
368 public:
NormalEquation()369 NormalEquation() {SetCoeff(1, 1, 1);}
NormalEquation(double c,double mean,double std)370 NormalEquation(double c, double mean, double std) {SetCoeff(c, mean, std);}
f(double x)371 double f(double x) {
372 double c = coeff[0];
373 double mean = coeff[1];
374 double std = coeff[2];
375 return c*exp(-0.5*sqr((x - mean)/std))/(std*sqrt(2*M_PI));
376 }
GetName()377 virtual String GetName() {return t_("Normal");}
378 virtual String GetEquation(int numDigits = 3) {
379 String c = FormatCoeff(0, numDigits);
380 String mean = FormatCoeff(1, numDigits);
381 String std = FormatCoeff(2, numDigits);
382 String ret = Format("%s/(%s*sqrt(2*PI))*e^(-1/2((x-%s)/%s))", c, std, mean, std);
383 ret.Replace("+ -", "- ");
384 return ret;
385 }
GuessCoeff(DataSource &)386 virtual void GuessCoeff(DataSource &) {}
_GuessCoeff(DataSource & series)387 virtual void _GuessCoeff(DataSource &series) {
388 double mean = series.AvgX();
389 double std = series.StdDevX();
390 double c = series.MaxY()*std*sqrt(2*M_PI);
391 SetCoeff(c, mean, std);
392 }
Fit(DataSource & series,double & r2)393 FitError Fit(DataSource &series, double &r2) {
394 _GuessCoeff(series);
395 return ExplicitEquation::Fit(series, r2);
396 }
Fit(DataSource & series)397 FitError Fit(DataSource &series) {double dummy; return Fit(series, dummy);}
SetDegree(int)398 void SetDegree(int ) {NEVER();}
399 };
400
401 class Rational1Equation : public ExplicitEquation {
402 public:
Rational1Equation()403 Rational1Equation() {SetCoeff(1, 0, 0);}
Rational1Equation(double c0,double c1,double c2)404 Rational1Equation(double c0, double c1, double c2) {SetCoeff(c0, c1, c2);}
f(double x)405 double f(double x) {return coeff[0]/(x + coeff[1]) + coeff[2];}
GetName()406 virtual String GetName() {return t_("Rational_1");}
407 virtual String GetEquation(int _numDigits = 3) {
408 String ret = Format("%s/(x + %s) + %s", FormatCoeff(0, _numDigits), FormatCoeff(1, _numDigits), FormatCoeff(2, _numDigits));
409 ret.Replace("+ -", "- ");
410 return ret;
411 }
GuessCoeff(DataSource &)412 virtual void GuessCoeff(DataSource &) {}
SetDegree(int)413 void SetDegree(int ) {NEVER();}
414 };
415
416 class Spline {
417 public:
Spline()418 Spline() {}
Spline(const Vector<double> & x,const Vector<double> & y)419 Spline(const Vector<double> &x, const Vector<double> &y) {Fit(x, y);}
Spline(const Eigen::VectorXd & x,const Eigen::VectorXd & y)420 Spline(const Eigen::VectorXd &x, const Eigen::VectorXd &y) {Fit(x, y);}
Spline(const double * x,const double * y,int n)421 Spline(const double *x, const double *y, int n) {Fit(x, y, n);}
Fit(const Vector<double> & x,const Vector<double> & y)422 void Fit(const Vector<double> &x, const Vector<double> &y) {Fit(x.begin(), y.begin(), x.GetCount());}
Fit(const Eigen::VectorXd & x,const Eigen::VectorXd & y)423 void Fit(const Eigen::VectorXd &x, const Eigen::VectorXd &y) {Fit(x.data(), y.data(), int(x.size()));}
424 void Fit(const double *x, const double *y, int n);
425 double f(double x) const;
426
427 private:
428 struct Coeff {double a, b, c, d, x;};
429 Buffer<Coeff> scoeff;
430 int nscoeff = 0;
431 };
432
433 class SplineEquation : public ExplicitEquation, public Spline {
434 public:
SplineEquation()435 SplineEquation() {}
f(double x)436 double f(double x) {return Spline::f(x);}
GetName()437 virtual String GetName() {return t_("Spline");}
SetDegree(int)438 void SetDegree(int ) {NEVER();}
GuessCoeff(DataSource &)439 void GuessCoeff(DataSource &) {NEVER();}
GetEquation(int)440 String GetEquation(int) {return t_("Spline");}
441 FitError Fit(DataSource &series, double &r2);
Fit(DataSource & series)442 FitError Fit(DataSource &series) {double dummy; return Fit(series, dummy);}
443 };
444
445 class Unit : public Moveable<Unit> {
446 public:
Unit()447 Unit() {SetNull();}
Unit(const Nuller &)448 Unit(const Nuller&) : Unit() {}
Unit(double _m,double _l,double _t)449 Unit(double _m, double _l, double _t) : m(_m), l(_l), t(_t) {}
GetString()450 String GetString() {
451 if (IsNullInstance())
452 return String();
453 String ret;
454 if (m != 0) {
455 ret << "Kg";
456 if (m != 1)
457 ret << "^" << m;
458 }
459 if (l != 0) {
460 if (!ret.IsEmpty())
461 ret << "*";
462 ret << "m";
463 if (l != 1)
464 ret << "^" << l;
465 }
466 if (t != 0) {
467 if (!ret.IsEmpty())
468 ret << "*";
469 ret << "sec";
470 if (t != 1)
471 ret << "^" << t;
472 }
473 return ret;
474 }
IsEqual(const Unit & un)475 bool IsEqual(const Unit &un) {return m == un.m && l == un.l && t == un.t;}
Mult(const Unit & un)476 void Mult(const Unit &un) {
477 m += un.m;
478 l += un.l;
479 t += un.t;
480 }
Div(const Unit & un)481 void Div(const Unit &un) {
482 m -= un.m;
483 l -= un.l;
484 t -= un.t;
485 }
Exp(double exp)486 void Exp(double exp) {
487 m *= exp;
488 l *= exp;
489 t *= exp;
490 }
Sqrt()491 void Sqrt() {
492 m /= 2.;
493 l /= 2.;
494 t /= 2.;
495 }
496
SetNull()497 void SetNull() {m = Null;}
IsNullInstance()498 bool IsNullInstance() const {return Upp::IsNull(m);}
IsAdim()499 bool IsAdim() const {return (m == 0) && (l == 0) && (t == 0);}
500
501 double m, l, t;
502 };
503
504 class doubleUnit : public Moveable<doubleUnit> {
505 public:
doubleUnit()506 doubleUnit() : doubleUnit(0) {}
doubleUnit(double _val)507 doubleUnit(double _val) : val(_val), sval(String::GetVoid()), unit(0, 0, 0) {}
doubleUnit(const Nuller &)508 doubleUnit(const Nuller&) {SetNull();}
509
510 double val;
511 String sval;
512 Unit unit;
513
Sum(const doubleUnit & d)514 void Sum(const doubleUnit &d) {
515 if (!(unit.IsEqual(d.unit) || IsNull(unit) || IsNull(d.unit)))
516 throw Exc(t_("Units does not match in summation"));
517 val += d.val;
518 }
Sub(const doubleUnit & d)519 void Sub(const doubleUnit &d) {
520 if (!(unit.IsEqual(d.unit) || IsNull(unit) || IsNull(d.unit)))
521 throw Exc(t_("Units does not match in substraction"));
522 val -= d.val;
523 }
Mult(const doubleUnit & d)524 void Mult(const doubleUnit &d) {
525 unit.Mult(d.unit);
526 val *= d.val;
527 }
Div(const doubleUnit & d)528 void Div(const doubleUnit &d) {
529 if (abs(d.val) < 1e-100)
530 throw Exc(t_("Division by zero"));
531 unit.Div(d.unit);
532 val /= d.val;
533 }
Neg()534 void Neg() {
535 val = -val;
536 }
Exp(const doubleUnit & d)537 void Exp(const doubleUnit &d) {
538 if (!(IsNull(d.unit) || d.unit.IsAdim()))
539 throw Exc(t_("Exponent cannot have units"));
540 unit.Mult(d.unit);
541 val = pow(val, d.val);
542 }
Sqrt()543 void Sqrt() {
544 if (val < 0)
545 throw Exc(t_("Negative number sqrt"));
546 val = sqrt(val);
547 unit.Sqrt();
548 }
ResParallel(const doubleUnit & d)549 void ResParallel(const doubleUnit &d) {
550 if (abs(val + d.val) < 1e-100 && abs(val*d.val) > 1e-100)
551 throw Exc(t_("Division by zero"));
552 if (!(unit.IsEqual(d.unit) || IsNull(unit) || IsNull(d.unit)))
553 throw Exc(t_("Units does not match in resistor parallel"));
554 if (abs(val*d.val) < 1e-100)
555 val = 0.0;
556 else
557 val = val*d.val/(val + d.val);
558 }
SetNull()559 void SetNull() {val = Null;}
IsNullInstance()560 bool IsNullInstance() const {return IsNull(unit) && IsNull(val);}
561 };
562
IsNull(const doubleUnit & r)563 template<> inline bool IsNull(const doubleUnit& r) {return r.val < DOUBLE_NULL_LIM;}
564
565 class CParserPP : public CParser {
566 public:
CParserPP()567 CParserPP() : CParser() {}
CParserPP(const char * ptr)568 CParserPP(const char *ptr) : CParser(ptr) {}
569
ReadIdPP()570 String ReadIdPP() {
571 if(!IsId())
572 ThrowError("missing id");
573 String result;
574 const char *b = term;
575 const char *p = b;
576
577 while (true) {
578 while (iscid(*p))
579 p++;
580 if ((*p) == '[') {
581 p++;
582 const char *p0 = p;
583 while ((*p) >= '0' && (*p) <= '9')
584 p++;
585 if (p0 == p)
586 ThrowError("empty vector index");
587 if ((*p) != ']')
588 ThrowError("wrong token found closing vector index");
589 else
590 p++;
591 } else if ((*p) == '.')
592 p++;
593 else
594 break;
595 }
596 term = p;
597 DoSpaces();
598 return String(b, (int)(uintptr_t)(p - b));
599 }
600 };
601
602 class EvalExpr {
603 public:
604 EvalExpr();
Clear()605 void Clear() {variables.Clear();}
606 doubleUnit Eval(String line);
607 doubleUnit AssignVariable(String var, String expr);
608 doubleUnit AssignVariable(String var, double d);
609 String EvalStr(String line, int numDigits = 3);
610 EvalExpr &SetCaseSensitivity(bool val = true) {noCase = !val; return *this;}
611 EvalExpr &SetErrorUndefined(bool val = true) {errorIfUndefined = val; return *this;}
612 EvalExpr &SetAllowString(bool val = true) {allowString = val; return *this;}
613
GetFunction(int id)614 const String &GetFunction(int id) {return functions.GetKey(id);}
GetFunctionsCount()615 int GetFunctionsCount() {return functions.GetCount();}
616
SetConstant(String name,doubleUnit value)617 void SetConstant(String name, doubleUnit value) {constants.GetAdd(name) = value;}
SetConstant(int id,doubleUnit value)618 void SetConstant(int id, doubleUnit value) {constants[id] = value;}
GetConstant(String name)619 const doubleUnit &GetConstant(String name) {return constants.Get(name, doubleUnit(Null));}
GetConstant(int id,String & name,doubleUnit & val)620 void GetConstant(int id, String &name, doubleUnit &val) {name = constants.GetKey(id); val = constants[id];}
GetConstantId(String & name)621 int GetConstantId(String &name) {return constants.Find(name);}
GetConstantsCount()622 int GetConstantsCount() {return constants.GetCount();}
623
GetVariable(String name)624 doubleUnit &GetVariable(String name) {
625 int id = FindVariable(name);
626 if (id >= 0)
627 return variables[id];
628 if (errorIfUndefined)
629 EvalThrowError(p, Format(t_("Unknown identifier '%s'"), name));
630 return variables.Add(name, Null);
631 }
GetVariable(int id)632 doubleUnit &GetVariable(int id) {return variables[id];}
GetVariable(int id,String & name,doubleUnit & val)633 void GetVariable(int id, String &name, doubleUnit &val) {name = variables.GetKey(id); val = variables[id];}
GetVariablesCount()634 int GetVariablesCount() {return variables.GetCount();}
635 void ClearVariables();
GetLastError()636 String &GetLastError() {return lastError;}
637
638 VectorMap<String, doubleUnit> constants;
639 VectorMap<String, doubleUnit (*)(doubleUnit)> functions;
640
641 CParserPP p;
642
643 static void EvalThrowError(CParserPP &p, const char *s);
644
FindVariable(String strId)645 virtual int FindVariable(String strId) {return variables.Find(strId);}
646
647 protected:
648 doubleUnit Exp(CParserPP& p);
649
SetVariable(String name,doubleUnit value)650 void SetVariable(String name, doubleUnit value) {
651 lastVariableSetId = variables.FindAdd(name);
652 variables[lastVariableSetId] = value;
653 }
SetVariable(int id,doubleUnit value)654 void SetVariable(int id, doubleUnit value) {
655 lastVariableSetId = id;
656 variables[id] = value;
657 }
FindAddVariable(String name)658 int FindAddVariable(String name) {
659 return lastVariableSetId = variables.FindAdd(name);
660 }
RemoveVariable(int id)661 void RemoveVariable(int id) {
662 variables.Remove(id);
663 }
664 bool noCase;
665 String lastError;
666 VectorMap<String, doubleUnit> variables;
667 bool errorIfUndefined;
668 bool allowString;
669 int lastVariableSetId = -1;
670
IsFunction(String str)671 bool IsFunction(String str) {return functions.Get(str, 0);}
IsConstant(String str)672 bool IsConstant(String str) {return !IsNull(GetConstant(str));}
673
674 private:
675 void *Functions_Get(CParserPP& p);
676 doubleUnit Term(CParserPP& p);
677 doubleUnit Pow(CParserPP& p);
678 doubleUnit Mul(CParserPP& p);
679
680 String TermStr(CParserPP& p, int numDigits);
681 String PowStr(CParserPP& p, int numDigits);
682 String MulStr(CParserPP& p, int numDigits);
683 String ExpStr(CParserPP& p, int numDigits);
684 };
685
686 class UserEquation : public ExplicitEquation {
687 public:
UserEquation()688 UserEquation() {}
689 UserEquation(String _name, String _strEquation, String varHoriz = "x") {Init(_name, _strEquation, varHoriz);}
690 void Init(String _name, String _strEquation, String varHoriz = "x") {
691 name = _name;
692 _strEquation.Replace(" ", "");
693 StringStream str(_strEquation);
694 Vector<String> parts = GetCsvLine(str, ';', CHARSET_DEFAULT);
695 if (parts.IsEmpty())
696 return;
697 strEquation = parts[0];
698 eval.Clear();
699 eval.SetConstant(varHoriz, doubleUnit(23));
700 idx = eval.GetConstantsCount() - 1;
701 eval.EvalStr(strEquation);
702 coeff.Clear();
703 varNames.Clear();
704 if (eval.GetVariablesCount() == 0)
705 coeff.SetCount(1);
706 else {
707 for (int i = 0; i < eval.GetVariablesCount(); ++i) {
708 String varName;
709 doubleUnit dummy;
710 eval.GetVariable(i, varName, dummy);
711 varNames << varName;
712 int istr;
713 for (istr = 1; istr < parts.GetCount(); ++istr) {
714 String strVar = varName + "=";
715 int ifound = parts[istr].Find(strVar);
716 if (ifound >= 0) {
717 double val = ScanDouble(parts[istr].Mid(strVar.GetCount()));
718 coeff << val;
719 break;
720 }
721 }
722 if (istr == parts.GetCount())
723 coeff << 0.1;
724 }
725 }
726 }
f(double x)727 double f(double x) {
728 eval.SetConstant(idx, doubleUnit(x));
729 for (int i = 0; i < varNames.GetCount(); ++i)
730 eval.AssignVariable(varNames[i], coeff[i]);
731 return eval.Eval(strEquation).val;
732 }
SetName(String _name)733 void SetName(String _name) {name = _name;}
GetName()734 virtual String GetName() {return name;}
735 virtual String GetEquation(int numDigits = 3) {return eval.EvalStr(strEquation, numDigits);}
GuessCoeff(DataSource &)736 virtual void GuessCoeff(DataSource &) {}
SetDegree(int)737 void SetDegree(int) {NEVER();}
738
739 private:
740 String name;
741 String strEquation;
742 Vector<String> varNames;
743 EvalExpr eval;
744 int idx;
745 };
746
747 }
748
749 #endif
750