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