[gnome-calculator/60-split-out-a-backend-library] gcalc: initial infrastructure for equations solving
- From: Daniel Espinosa Ortiz <despinosa src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-calculator/60-split-out-a-backend-library] gcalc: initial infrastructure for equations solving
- Date: Thu, 3 Jan 2019 22:58:59 +0000 (UTC)
commit 5f8cc87dcadb1be8f97de3319398dbc394723f4d
Author: Daniel Espinosa Ortiz <esodan gmail com>
Date: Thu Jan 3 16:52:30 2019 -0600
gcalc: initial infrastructure for equations solving
gcalc/gcalc-constant.vala | 5 +++
gcalc/gcalc-expression.vala | 1 +
gcalc/gcalc-gconstant.vala | 77 ++++++++++++++++++++++++++++++++++++++----
gcalc/gcalc-gexpression.vala | 4 +++
gcalc/gcalc-gpolynomial.vala | 28 +++++++++++++++
gcalc/gcalc-gresult.vala | 4 ++-
gcalc/gcalc-term.vala | 41 +++++++++++++++++++++-
gcalc/meson.build | 1 +
tests/gcalc-parsing.vala | 5 +++
tests/gcalc-solving-basic.vala | 43 ++++++++++++++++++-----
vapi/mpc.vapi | 14 ++++++++
11 files changed, 205 insertions(+), 18 deletions(-)
---
diff --git a/gcalc/gcalc-constant.vala b/gcalc/gcalc-constant.vala
index e8707a25..21a0670a 100644
--- a/gcalc/gcalc-constant.vala
+++ b/gcalc/gcalc-constant.vala
@@ -19,6 +19,11 @@
* Daniel Espinosa <esodan gmail com>
*/
public interface GCalc.Constant : Object, Expression {
+ public abstract double real ();
+ public abstract double imag ();
public abstract void zero ();
+ public abstract Constant add (Constant c);
+ public abstract Constant multiply (Constant c);
+ public abstract Constant divide (Constant c);
}
diff --git a/gcalc/gcalc-expression.vala b/gcalc/gcalc-expression.vala
index 0ea3554f..8842a4e8 100644
--- a/gcalc/gcalc-expression.vala
+++ b/gcalc/gcalc-expression.vala
@@ -21,5 +21,6 @@
public interface GCalc.Expression : Object {
public abstract ExpressionContainer expressions { get; }
public abstract string to_string ();
+ public abstract Result solve ();
}
diff --git a/gcalc/gcalc-gconstant.vala b/gcalc/gcalc-gconstant.vala
index 4658db80..463864f0 100644
--- a/gcalc/gcalc-gconstant.vala
+++ b/gcalc/gcalc-gconstant.vala
@@ -19,26 +19,89 @@
* Daniel Espinosa <esodan gmail com>
*/
public class GCalc.GConstant : GExpression, Constant {
- private MPFR.Real real_value = MPFR.Real (1000);
+ private MPC.Complex _complex = MPC.Complex (1000);
+ private bool imaginary = false;
+
+ internal unowned MPC.Complex get_complex () { return _complex; }
construct {
- real_value.set_zero ();
+ _complex.set_double (0.0);
+ }
+ internal GConstant.complex (MPC.Complex complex) {
+ _complex.set (complex);
}
public GConstant.integer (int val) {
- real_value.set_signed_integer ((long) val);
+ _complex.set_double (val);
}
public GConstant.unsigned_integer (uint val) {
- real_value.set_unsigned_integer ((ulong) val);
+ _complex.set_double (val);
}
public GConstant.@double (double val) {
- real_value.set_double (val);
+ _complex.set_double (val);
+ }
+ public GConstant.new_imag (double real, double imag) {
+ _complex.set_double (real, imag);
+ imaginary = true;
}
// Constant Interface
- public void zero () { real_value.set_zero (); }
+ public double real () {
+ return _complex.get_real_double ();
+ }
+ public double imag () {
+ return _complex.get_imag_double ();
+ }
+ public void zero () {
+ MPFR.Real r = MPFR.Real (1000);
+ r.set_zero ();
+ _complex.set_mpreal (r);
+ }
+ public Constant add (Constant c)
+ requires (c is GConstant)
+ {
+ var res = MPC.Complex (1000);
+ var p1 = MPC.Complex (1000);
+ p1.set ((c as GConstant).get_complex ());
+ res.add (_complex, p1);
+ var nc = new GConstant.complex (res);
+ return nc as Constant;
+ }
+ public Constant subtract (Constant c)
+ requires (c is GConstant)
+ {
+ var res = MPC.Complex (1000);
+ var p1 = MPC.Complex (1000);
+ p1.set ((c as GConstant).get_complex ());
+ res.subtract (_complex, p1);
+ var nc = new GConstant.complex (res);
+ return nc as Constant;
+ }
+ public Constant multiply (Constant c)
+ requires (c is GConstant)
+ {
+ var res = MPC.Complex (1000);
+ var p1 = MPC.Complex (1000);
+ p1.set ((c as GConstant).get_complex ());
+ res.multiply (_complex, p1);
+ var nc = new GConstant.complex (res);
+ return nc as Constant;
+ }
+ public Constant divide (Constant c)
+ requires (c is GConstant)
+ {
+ var res = MPC.Complex (1000);
+ var p1 = MPC.Complex (1000);
+ p1.set ((c as GConstant).get_complex ());
+ res.divide (_complex, p1);
+ var nc = new GConstant.complex (res);
+ return nc as Constant;
+ }
// Expression interface
public override string to_string () {
- return ""; // FIXME: write down string representation
+ if (imaginary) {
+ return MPC.Complex.to_string (10, 10, _complex);
+ }
+ return "%g".printf (real ());
}
}
diff --git a/gcalc/gcalc-gexpression.vala b/gcalc/gcalc-gexpression.vala
index ec56fd68..23a77d47 100644
--- a/gcalc/gcalc-gexpression.vala
+++ b/gcalc/gcalc-gexpression.vala
@@ -24,5 +24,9 @@ public class GCalc.GExpression : Object, Expression {
public new virtual string to_string () {
return "";
}
+ public new virtual Result solve () {
+ var e = new GErrorResult ("Invalid expression");
+ return new GResult.with_error (this, e as ErrorResult);
+ }
}
diff --git a/gcalc/gcalc-gpolynomial.vala b/gcalc/gcalc-gpolynomial.vala
index b3cf610d..09f3e550 100644
--- a/gcalc/gcalc-gpolynomial.vala
+++ b/gcalc/gcalc-gpolynomial.vala
@@ -19,5 +19,33 @@
* Daniel Espinosa <esodan gmail com>
*/
public class GCalc.GPolynomial : GExpression, Polynomial {
+ public override Result solve () {
+ Expression res = null;
+ Term current = null;
+ foreach (Expression e in expressions) {
+ var r = e.solve ();
+ if (!r.is_valid) {
+ return r;
+ }
+ if (r.expression is Term) {
+ var t = r.expression as Term;
+ if (current == null) {
+ current = t;
+ continue;
+ }
+ try {
+ current.sum (t);
+ } catch (GLib.Error err) {
+ var nerr = new GErrorResult (err.message);
+ return new GResult.with_error ((Expression) new GExpression (), (ErrorResult) nerr) as Result;
+ }
+ }
+ if (r.expression is Constant) {
+ res = r.expression;
+ break;
+ }
+ }
+ return new GResult (res) as Result;
+ }
}
diff --git a/gcalc/gcalc-gresult.vala b/gcalc/gcalc-gresult.vala
index 5cb4d29b..3d9998f4 100644
--- a/gcalc/gcalc-gresult.vala
+++ b/gcalc/gcalc-gresult.vala
@@ -18,7 +18,7 @@
* Authors:
* Daniel Espinosa <esodan gmail com>
*/
-public class GCalc.GResult : Object {
+public class GCalc.GResult : Object, Result {
private Expression _expression;
private ErrorResult _error;
public GResult (Expression exp) {
@@ -29,6 +29,8 @@ public class GCalc.GResult : Object {
_expression = exp;
_error = error;
}
+
+ // Result
public bool is_valid { get { return _error == null; } }
public string to_string () {
return expression.to_string ();
diff --git a/gcalc/gcalc-term.vala b/gcalc/gcalc-term.vala
index db11643b..258ba529 100644
--- a/gcalc/gcalc-term.vala
+++ b/gcalc/gcalc-term.vala
@@ -18,5 +18,44 @@
* Authors:
* Daniel Espinosa <esodan gmail com>
*/
-public interface GCalc.Term : Object, Expression {}
+public interface GCalc.Term : Object, Expression {
+ public virtual Expression sum (Term t) throws GLib.Error {
+ if (t.expressions.get_n_items () == 0) {
+ return this;
+ }
+ Expression current = null;
+ Operator current_operator = null;
+ bool first = true;
+ foreach (Expression e in expressions) {
+ if (e is Operator) {
+ if (!(e is Minus || e is Plus) && first) {
+ throw new TermError.INVALID_OPERATOR ("Incorrect position for operator in expression");
+ }
+ if (e is Minus && first) {
+ current = new GConstant.@double (-1.0);
+ first = false;
+ }
+ current_operator = e as Operator;
+ } else if (e is Constant) {
+ if (current == null) {
+ current = e;
+ first = false;
+ } else {
+ if (current is Constant) {
+ if (current_operator != null) {
+ if (e is Minus && e is Multiply) {
+ current = (current as Constant).multiply (e as Constant);
+ }
+ }
+ }
+ }
+ }
+ }
+ return current;
+ }
+}
+
+public errordomain GCalc.TermError {
+ INVALID_OPERATOR
+}
diff --git a/gcalc/meson.build b/gcalc/meson.build
index bbc268f8..2b0936c2 100644
--- a/gcalc/meson.build
+++ b/gcalc/meson.build
@@ -90,6 +90,7 @@ deps = [
libxml,
libsoup,
vala_dep,
+ libmath,
gee
]
diff --git a/tests/gcalc-parsing.vala b/tests/gcalc-parsing.vala
index 06a4fc9e..515a05ec 100644
--- a/tests/gcalc-parsing.vala
+++ b/tests/gcalc-parsing.vala
@@ -504,6 +504,11 @@ class Tests {
warning ("Error: %s", error.message);
}
});
+ Test.add_func ("/gcalc/parser/constant/to_string",
+ ()=>{
+ Constant c = new GConstant.@double (-1.0) as Constant;
+ assert ("-1" in c.to_string ());
+ });
return Test.run ();
}
}
diff --git a/tests/gcalc-solving-basic.vala b/tests/gcalc-solving-basic.vala
index 932f4e38..5d54ee31 100644
--- a/tests/gcalc-solving-basic.vala
+++ b/tests/gcalc-solving-basic.vala
@@ -23,16 +23,41 @@ class Tests {
{
GLib.Intl.setlocale (GLib.LocaleCategory.ALL, "");
Test.init (ref args);
- Test.add_func ("/gcalc/parser/constant/integer",
+ Test.add_func ("/gcalc/solve/constant/add",
()=>{
- try {
- var parser = new Parser ();
- var eqman = new GMathEquationManager ();
- parser.parse ("1", eqman);
-
- } catch (GLib.Error error) {
- warning ("Error: %s", error.message);
- }
+ var c1 = new GConstant.@double (3.0);
+ var c2 = new GConstant.@double (3.0);
+ var c3 = c1.add (c2);
+ assert (c3 != null);
+ message (c3.to_string ());
+ assert (c3.real () == 6.0);
+ });
+ Test.add_func ("/gcalc/solve/constant/subtract",
+ ()=>{
+ var c1 = new GConstant.@double (9.0);
+ var c2 = new GConstant.@double (3.0);
+ var c3 = c1.subtract (c2);
+ assert (c3 != null);
+ message (c3.to_string ());
+ assert (c3.real () == 6.0);
+ });
+ Test.add_func ("/gcalc/solve/constant/multiply",
+ ()=>{
+ var c1 = new GConstant.@double (3.0);
+ var c2 = new GConstant.@double (3.0);
+ var c3 = c1.multiply (c2);
+ assert (c3 != null);
+ message (c3.to_string ());
+ assert (c3.real () == 9.0);
+ });
+ Test.add_func ("/gcalc/solve/constant/devide",
+ ()=>{
+ var c1 = new GConstant.@double (9.0);
+ var c2 = new GConstant.@double (3.0);
+ var c3 = c1.divide (c2);
+ assert (c3 != null);
+ message (c3.to_string ());
+ assert (c3.real () == 3.0);
});
return Test.run ();
}
diff --git a/vapi/mpc.vapi b/vapi/mpc.vapi
index 00e6c138..bc818344 100644
--- a/vapi/mpc.vapi
+++ b/vapi/mpc.vapi
@@ -121,5 +121,19 @@ namespace MPC {
public int asinh (Complex op, Round rnd = Round.NEAREST);
public int acosh (Complex op, Round rnd = Round.NEAREST);
public int atanh (Complex op, Round rnd = Round.NEAREST);
+
+ public double get_real_double () {
+ var r = MPFR.Real (1000);
+ r.set (get_real ().val);
+ return r.get_double ();
+ }
+ public double get_imag_double () {
+ var i = MPFR.Real (1000);
+ i.set (get_imag ().val);
+ return i.get_double ();
+ }
+
+ [CCode (cname="mpc_get_str")]
+ public static string to_string (int @base, size_t digits, Complex op, Round rnd = Round.NEAREST);
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]