diff --git a/Symbolism/Symbolism.cs b/Symbolism/Symbolism.cs
index e83d385..b038f36 100644
--- a/Symbolism/Symbolism.cs
+++ b/Symbolism/Symbolism.cs
@@ -23,6 +23,8 @@ namespace Symbolism
{
public abstract class MathObject
{
+ public const string MathmlDeclaration = "";
+ public const string EmptyMathmlDeclaration = "{}";
//////////////////////////////////////////////////////////////////////
public static implicit operator MathObject(int n) => new Integer(n);
@@ -137,6 +139,13 @@ public override string ToString()
throw new Exception();
}
+ public virtual string ToMathml(bool useMathmlDeclaration = false) => string.Empty;
+
+ protected static string ToMathml(string result, bool useMathmlDeclaration = false)
+ {
+ return useMathmlDeclaration ? string.Format(MathmlDeclaration, result) : result;
+ }
+
public virtual MathObject Numerator() => this;
public virtual MathObject Denominator() => 1;
@@ -145,6 +154,7 @@ public override bool Equals(object obj)
{ throw new Exception("MathObject.Equals called - abstract class"); }
public override int GetHashCode() => base.GetHashCode();
+
}
public class Equation : MathObject
@@ -171,6 +181,15 @@ public override string FullForm()
throw new Exception();
}
+ public override string ToMathml(bool useMathmlDeclaration = false)
+ {
+ if (Operator == Operators.Equal) return ToMathml(a.ToMathml() + "=" + b.ToMathml(), useMathmlDeclaration);
+ if (Operator == Operators.NotEqual) return ToMathml(a.ToMathml() + "≠" + b.ToMathml(), useMathmlDeclaration);
+ if (Operator == Operators.LessThan) return ToMathml(a.ToMathml() + "<" + b.ToMathml(), useMathmlDeclaration);
+ if (Operator == Operators.GreaterThan) return ToMathml(a.ToMathml() + ">" + b.ToMathml(), useMathmlDeclaration);
+ throw new Exception();
+ }
+
public override bool Equals(object obj) =>
obj is Equation &&
a.Equals((obj as Equation).a) &&
@@ -272,7 +291,7 @@ public class Integer : Number
public Integer(int n) { val = n; }
public Integer(BigInteger n) { val = n; }
-
+
public static implicit operator Integer(BigInteger n) => new Integer(n);
// public static MathObject operator *(MathObject a, MathObject b) => new Product(a, b).Simplify();
@@ -288,6 +307,11 @@ public class Integer : Number
public override int GetHashCode() => val.GetHashCode();
public override DoubleFloat ToDouble() => new DoubleFloat((double)val);
+
+ public override string ToMathml(bool useMathmlDeclaration = false)
+ {
+ return ToMathml($"{val}", useMathmlDeclaration);
+ }
}
public class DoubleFloat : Number
@@ -321,6 +345,13 @@ public override bool Equals(object obj)
public override int GetHashCode() => val.GetHashCode();
public override DoubleFloat ToDouble() => this;
+
+ public override string ToMathml(bool useMathmlDeclaration = false)
+ {
+ var arr = val.ToString().Split('.');
+ var rest = arr.Length > 1 ? $".{arr[1]}" : string.Empty;
+ return ToMathml($"{arr[0]}{rest}", useMathmlDeclaration);
+ }
}
public class Fraction : Number
@@ -346,16 +377,116 @@ public override bool Equals(object obj) =>
public override MathObject Numerator() => numerator;
public override MathObject Denominator() => denominator;
+
+ public override string ToMathml(bool useMathmlDeclaration = false)
+ {
+ if (new Norm(numerator).Simplify() < denominator || numerator == denominator)
+ {
+ return ToMathml($"{numerator.ToMathml()}{denominator.ToMathml()}", useMathmlDeclaration);
+ }
+
+ BigInteger rem;
+
+ var quot = BigInteger.DivRem(numerator.val, denominator.val, out rem);
+ return new MixedNumber(new Integer(quot), new Norm(rem).Simplify() as Integer, denominator).ToMathml(useMathmlDeclaration);
+ }
+ }
+
+ public class MixedNumber : Number
+ {
+ public Integer quotient;
+ public Integer numerator;
+ public Integer denominator;
+
+ public MixedNumber(Integer q, Integer a, Integer b)
+ {
+ quotient = q;
+ numerator = a;
+ denominator = b;
+ }
+
+ public override string FullForm() => $"({quotient} + {numerator} / {denominator})";
+
+ public override string ToMathml(bool useMathmlDeclaration = false)
+ {
+ return ToMathml($"{quotient.ToMathml()}{numerator.ToMathml()}{denominator.ToMathml()}", useMathmlDeclaration);
+ }
+
+ public Fraction ToFraction() => new Fraction((quotient * denominator + numerator) as Integer, denominator);
+ public override DoubleFloat ToDouble() => this.ToFraction().ToDouble();
+ //////////////////////////////////////////////////////////////////////
+
+ public override bool Equals(object obj) =>
+ quotient == (obj as MixedNumber)?.quotient
+ &&
+ numerator == (obj as Fraction)?.numerator
+ &&
+ denominator == (obj as Fraction)?.denominator;
+
+ public override int GetHashCode() => new { quotient, numerator, denominator }.GetHashCode();
+
+ public override MathObject Numerator() => numerator;
+
+ public MathObject Quotient() => quotient;
+
+ public override MathObject Denominator() => denominator;
+ }
+
+
+ public class Norm : Function
+ {
+ public Norm(MathObject x) : base("norm", null, new List { x})
+ {
+ this.proc = proc??NormProc;
+ }
+
+ MathObject NormProc(MathObject[] ls)
+ {
+ if (ls[0] == null)
+ {
+ return 0;
+ }
+
+ if (ls[0] is Number)
+ {
+ if ((Number)ls[0] > new DoubleFloat(0) || (Number)ls[0] == new DoubleFloat(0))
+ {
+ return ls[0];
+ }
+
+ return -1 * ls[0];
+ }
+
+ if (ls[0] is Product && ((Product)ls[0]).elts[0] == -1)
+ {
+ return new Norm(-1 * ls[0]);
+ }
+
+ return new Norm(ls[0]);
+ }
+
+ //public override bool Equals(object obj) =>
+ // GetType() == obj.GetType() &&
+ // name == (obj as Function).name &&
+ // this.Simplify() == ((Norm)obj).Simplify();
+
+ public override int GetHashCode() => new { name, args }.GetHashCode();
+
+ public override string ToMathml(bool useMathmlDeclaration = false)
+ {
+ return ToMathml($"{args[0].ToMathml()}", useMathmlDeclaration);
+ }
}
+
public static class Rational
{
static BigInteger Div(BigInteger a, BigInteger b)
{ BigInteger rem; return BigInteger.DivRem(a, b, out rem); }
-
+
static BigInteger Rem(BigInteger a, BigInteger b)
{ BigInteger rem; BigInteger.DivRem(a, b, out rem); return rem; }
-
+
static BigInteger Gcd(BigInteger a, BigInteger b)
{
BigInteger r;
@@ -377,13 +508,13 @@ public static MathObject SimplifyRationalNumber(MathObject u)
var u_ = (Fraction)u;
var n = u_.numerator.val;
var d = u_.denominator.val;
-
+
if (Rem(n, d) == 0) return Div(n, d);
var g = Gcd(n, d);
-
+
if (d > 0) return new Fraction(Div(n, g), Div(d, g));
-
+
if (d < 0) return new Fraction(Div(-n, g), Div(-d, g));
}
@@ -437,7 +568,7 @@ public static Integer Denominator(MathObject u)
throw new Exception();
}
- public static Fraction EvaluateSum(MathObject v, MathObject w) =>
+ public static Fraction EvaluateSum(MathObject v, MathObject w) =>
// a / b + c / d
// a d / b d + c b / b d
@@ -446,13 +577,13 @@ public static Fraction EvaluateSum(MathObject v, MathObject w) =>
new Fraction(
Numerator(v) * Denominator(w) + Numerator(w) * Denominator(v),
Denominator(v) * Denominator(w));
-
+
public static Fraction EvaluateDifference(MathObject v, MathObject w) =>
new Fraction(
Numerator(v) * Denominator(w) - Numerator(w) * Denominator(v),
Denominator(v) * Denominator(w));
- public static Fraction EvaluateProduct(MathObject v, MathObject w) =>
+ public static Fraction EvaluateProduct(MathObject v, MathObject w) =>
new Fraction(
Numerator(v) * Numerator(w),
Denominator(v) * Denominator(w));
@@ -474,7 +605,7 @@ public static MathObject EvaluatePower(MathObject v, BigInteger n)
if (n > 0) return EvaluateProduct(EvaluatePower(v, n - 1), v);
if (n == 0) return 1;
-
+
if (n == -1) return new Fraction(Denominator(v), Numerator(v));
if (n < -1)
@@ -484,7 +615,7 @@ public static MathObject EvaluatePower(MathObject v, BigInteger n)
return EvaluatePower(s, -n);
}
}
-
+
if (n >= 1) return 0;
if (n <= 0) return new Undefined();
@@ -507,7 +638,7 @@ public static MathObject SimplifyRNERec(MathObject u)
var v = SimplifyRNERec(((Difference)u).elts[0]);
if (v == new Undefined()) return v;
-
+
return EvaluateProduct(-1, v);
}
@@ -591,6 +722,11 @@ public class Symbol : MathObject
public override bool Equals(Object obj) =>
obj is Symbol ? name == (obj as Symbol).name : false;
+
+ public override string ToMathml(bool useMathmlDeclaration = false)
+ {
+ return ToMathml(string.Format("{0}", name), useMathmlDeclaration);
+ }
}
public static class ListConstructor
@@ -602,9 +738,9 @@ public static class ListConstructor
public static class ListUtils
{
- public static ImmutableList Cons(this ImmutableList obj, MathObject elt) =>
+ public static ImmutableList Cons(this ImmutableList obj, MathObject elt) =>
obj.Insert(0, elt);
-
+
public static ImmutableList Cdr(this ImmutableList obj) => obj.RemoveAt(0);
public static bool equal(ImmutableList a, ImmutableList b)
@@ -625,11 +761,11 @@ public class Function : MathObject
{
public delegate MathObject Proc(params MathObject[] ls);
- public readonly String name;
+ public String name { get; protected set; }
- public readonly Proc proc;
-
- public readonly ImmutableList args;
+ public Proc proc { get; protected set; }
+
+ public ImmutableList args { get; protected set; }
public Function(string name, Proc proc, IEnumerable args)
{
@@ -637,7 +773,7 @@ public Function(string name, Proc proc, IEnumerable args)
this.proc = proc;
this.args = ImmutableList.CreateRange(args);
}
-
+
public override bool Equals(object obj) =>
GetType() == obj.GetType() &&
name == (obj as Function).name &&
@@ -659,7 +795,7 @@ public static class FunctionExtensions
// // return new T() { args = obj.args.Select(proc).ToList() }.Simplify();
// // return
-
+
//}
}
@@ -675,7 +811,7 @@ static MathObject AndProc(MathObject[] ls)
if (ls.Any(elt => elt == true))
return new And(ls.Where(elt => elt != true).ToArray()).Simplify();
-
+
if (ls.Any(elt => elt is And))
{
var items = new List();
@@ -692,7 +828,7 @@ static MathObject AndProc(MathObject[] ls)
return new And(ls);
}
-
+
public And(params MathObject[] ls) : base("and", AndProc, ls) { }
public And() : base("and", AndProc, new List()) { }
@@ -704,9 +840,14 @@ public MathObject Add(MathObject obj) =>
public MathObject AddRange(IEnumerable ls) =>
And.FromRange(args.AddRange(ls)).Simplify();
-
- public MathObject Map(Func proc) =>
+
+ public MathObject Map(Func proc) =>
And.FromRange(args.Select(proc)).Simplify();
+
+ public override string ToMathml(bool useMathmlDeclaration = false)
+ {
+ return ToMathml($"{string.Join(",", args.ConvertAll(arg => arg.ToMathml()))}", useMathmlDeclaration);
+ }
}
public class Or : Function
@@ -723,7 +864,7 @@ static MathObject OrProc(params MathObject[] ls)
if (ls.Any(elt => (elt is Bool) && (elt as Bool).val)) return new Bool(true);
if (ls.All(elt => (elt is Bool) && (elt as Bool).val == false)) return new Bool(false);
-
+
if (ls.Any(elt => elt is Or))
{
var items = new List();
@@ -733,13 +874,13 @@ static MathObject OrProc(params MathObject[] ls)
if (elt is Or) items.AddRange((elt as Or).args);
else items.Add(elt);
}
-
+
return Or.FromRange(items).Simplify();
}
return new Or(ls);
}
-
+
public Or(params MathObject[] ls) : base("or", OrProc, ls) { }
public Or() : base("or", OrProc, new List()) { }
@@ -747,6 +888,11 @@ public Or(params MathObject[] ls) : base("or", OrProc, ls) { }
public static Or FromRange(IEnumerable ls) => new Or(ls.ToArray());
public MathObject Map(Func proc) => Or.FromRange(args.Select(proc)).Simplify();
+
+ public override string ToMathml(bool useMathmlDeclaration = false)
+ {
+ return ToMathml($"{string.Join(",", args.ConvertAll(arg => arg.ToMathml()))}", useMathmlDeclaration);
+ }
}
public static class OrderRelation
@@ -759,7 +905,7 @@ public static MathObject Term(this MathObject u)
{
if (u is Product && ((Product)u).elts[0] is Number)
return Product.FromRange((u as Product).elts.Cdr());
- // return (u as Product).Cdr()
+ // return (u as Product).Cdr()
if (u is Product) return u;
@@ -829,7 +975,7 @@ public static bool Compare(MathObject u, MathObject v)
return O3(
(u as Product).elts.Reverse(),
(v as Product).elts.Reverse());
-
+
if (u is Sum && v is Sum)
return O3(
(u as Sum).elts.Reverse(),
@@ -938,7 +1084,7 @@ public MathObject Simplify()
return Rational.SimplifyRNE(new Power(v, n));
if (v is DoubleFloat && w is Integer)
- return new DoubleFloat(Math.Pow(((DoubleFloat)v).val, (double) ((Integer)w).val));
+ return new DoubleFloat(Math.Pow(((DoubleFloat)v).val, (double)((Integer)w).val));
if (v is DoubleFloat && w is Fraction)
return new DoubleFloat(Math.Pow(((DoubleFloat)v).val, ((Fraction)w).ToDouble().val));
@@ -954,7 +1100,7 @@ public MathObject Simplify()
if (v is Product && w is Integer)
return (v as Product).Map(elt => elt ^ w);
-
+
return new Power(v, w);
}
@@ -977,12 +1123,30 @@ public override MathObject Denominator()
}
public override int GetHashCode() => new { bas, exp }.GetHashCode();
+
+ public override string ToMathml(bool useMathmlDeclaration = false)
+ {
+ if (exp == new Integer(1) / new Integer(2))
+ {
+ return ToMathml($"{bas.ToMathml()}", useMathmlDeclaration);
+ }
+
+ if (exp is Fraction && (exp as Fraction).numerator == 1)
+ {
+ return ToMathml($"{bas.ToMathml()}{(exp as Fraction).denominator.ToMathml()}", useMathmlDeclaration);
+ }
+
+ return ToMathml(string.Format("{0}{1}",
+ bas.Precedence() < Precedence() ? $"{bas.ToMathml()}" : $"{bas.ToMathml()}",
+ exp.Precedence() < Precedence() ? $"{exp.ToMathml()}" : $"{exp.ToMathml()}"), useMathmlDeclaration);
+
+ }
}
public class Product : MathObject
{
public readonly ImmutableList elts;
-
+
public Product(params MathObject[] ls) => elts = ImmutableList.Create(ls);
public static Product FromRange(IEnumerable ls) => new Product(ls.ToArray());
@@ -1050,7 +1214,7 @@ static ImmutableList SimplifyDoubleNumberProduct(DoubleFloat a, Numb
if (b is Integer) val = a.val * (double)((Integer)b).val;
if (b is Fraction) val = a.val * ((Fraction)b).ToDouble().val;
-
+
if (val == 1.0) return ImmutableList.Create();
return ImList(new DoubleFloat(val));
@@ -1084,7 +1248,7 @@ public static ImmutableList RecursiveSimplify(ImmutableList();
return ImList(P);
@@ -1099,7 +1263,7 @@ public static ImmutableList RecursiveSimplify(ImmutableList();
return ImList(res);
@@ -1137,9 +1301,9 @@ public MathObject Simplify()
// Without the below, the following throws an exception:
// sqrt(a * b) * (sqrt(a * b) / a) / c
-
+
if (res.Any(elt => elt is Product)) return Product.FromRange(res).Simplify();
-
+
return Product.FromRange(res);
}
@@ -1151,13 +1315,21 @@ public override MathObject Denominator() =>
public MathObject Map(Func proc) =>
Product.FromRange(elts.Select(proc)).Simplify();
+
+ public override string ToMathml(bool useMathmlDeclaration = false)
+ {
+ return ToMathml(string.Join("·", elts.ConvertAll(elt => elt.Precedence() < Precedence() ? $"{elt.ToMathml()}" : $"{elt.ToMathml()}")), useMathmlDeclaration);
+ }
}
public class Sum : MathObject
{
public readonly ImmutableList elts;
- public Sum(params MathObject[] ls) { elts = ImmutableList.Create(ls); }
+ public Sum(params MathObject[] ls)
+ {
+ elts = ImmutableList.Create(ls);
+ }
public static Sum FromRange(IEnumerable ls) => new Sum(ls.ToArray());
@@ -1201,7 +1373,7 @@ static ImmutableList SimplifyDoubleNumberSum(DoubleFloat a, Number b
if (b is Fraction) val = a.val + ((Fraction)b).ToDouble().val;
if (val == 0.0) return ImmutableList.Create();
-
+
return ImmutableList.Create(new DoubleFloat(val));
}
@@ -1239,7 +1411,7 @@ static ImmutableList RecursiveSimplify(ImmutableList elt
(elts[1] is Integer || elts[1] is Fraction))
{
var P = Rational.SimplifyRNE(new Sum(elts[0], elts[1]));
-
+
if (P == 0) return ImmutableList.Create();
return ImList(P);
@@ -1312,6 +1484,37 @@ public override string StandardForm()
public MathObject Map(Func proc) =>
Sum.FromRange(elts.Select(proc)).Simplify();
+
+ public override string ToMathml(bool useMathmlDeclaration = false)
+ {
+ string mathmlResult = string.Empty;
+ int count = 0;
+ foreach (var item in elts)
+ {
+ if (item is Product && (item as Product).elts[0] is Number)
+ {
+ if (((item as Product).elts[0] as Number).ToDouble().val < 0)
+ {
+ mathmlResult = string.Concat(mathmlResult, "-", (-1 * item).ToMathml());
+ }
+ else
+ {
+ mathmlResult = string.Concat(mathmlResult, count == 0 ? string.Empty : "+", item.ToMathml());
+ }
+ }
+ else
+ {
+ mathmlResult = string.Concat(mathmlResult, count == 0 ? string.Empty : "+", item.ToMathml());
+ }
+
+ count++;
+ }
+
+ var result = mathmlResult;
+ return ToMathml(result, useMathmlDeclaration);
+
+ //return String.Join("+", elts.ConvertAll(elt => elt.Precedence() < Precedence() ? $"{elt.ToMathml()})" : $"{elt.ToMathml()}"));
+ }
}
class Difference : MathObject
@@ -1333,7 +1536,7 @@ public MathObject Simplify()
class Quotient : MathObject
{
public readonly ImmutableList elts;
-
+
public Quotient(params MathObject[] ls) => elts = ImmutableList.Create(ls);
public MathObject Simplify() => elts[0] * (elts[1] ^ -1);
diff --git a/Symbolism/Utils.cs b/Symbolism/Utils.cs
index 73d8d6a..ecaee28 100644
--- a/Symbolism/Utils.cs
+++ b/Symbolism/Utils.cs
@@ -6,42 +6,18 @@ namespace Symbolism.Utils
{
public static class Extensions
{
- public static T Disp(this T obj)
- {
- Console.WriteLine(obj);
- return obj;
- }
-
- public static T Disp(this T obj, string format)
- {
- Console.WriteLine(string.Format(format, obj));
- return obj;
- }
-
- public static MathObject DispLong(this MathObject obj, int indent = 0, bool comma = false)
- {
- if (obj is Or || obj is And)
- {
- Console.WriteLine(new String(' ', indent) + (obj as Function).name + "(");
-
- var i = 0;
-
- foreach (var elt in (obj as Function).args)
- {
- if (i < (obj as Function).args.Count - 1)
- elt.DispLong(indent + 2, comma: true);
- else
- elt.DispLong(indent + 2);
-
- i++;
- }
-
- Console.WriteLine(new String(' ', indent) + ")" + (comma ? "," : ""));
- }
-
- else Console.WriteLine(new String(' ', indent) + obj + (comma ? "," : ""));
-
- return obj;
- }
+ //public static T Disp(this T obj)
+ //{
+ // Console.WriteLine(obj);
+ // return obj;
+ //}
+
+ //public static T Disp(this T obj, string format)
+ //{
+ // Console.WriteLine(string.Format(format, obj));
+ // return obj;
+ //}
+
+
}
}
diff --git a/Tests/Tests.cs b/Tests/Tests.cs
index 842bea9..1e77204 100644
--- a/Tests/Tests.cs
+++ b/Tests/Tests.cs
@@ -6776,5 +6776,35 @@ public void PSE_5E_Example_8_5()
.AssertEqTo(ΔE == -302.0);
}
}
+
+ [Fact]
+ public void SummeryTest()
+ {
+ var expected = "";
+ var mo = new Sum(new Integer(5), 6);
+ var mathml = mo.ToMathml(true);
+ Assert.Equal(expected, mathml);
+
+ expected = "";
+ mo = new Sum(new Symbol("x"), new Symbol("y"));
+ mathml = mo.ToMathml(true);
+ Assert.Equal(expected, mathml);
+
+ }
+
+ [Fact]
+ public void DotTest()
+ {
+ var expected = "";
+ var mo = new Product(new Integer(5), 6);
+ var mathml = mo.ToMathml(true);
+ Assert.Equal(expected, mathml);
+
+ expected = "";
+ mo = new Product(new Symbol("x"), new Symbol("y"), new Symbol("z"));
+ mathml = mo.ToMathml(true);
+ Assert.Equal(expected, mathml);
+
+ }
}
}
diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj
index afddea6..fb9dfa2 100644
--- a/Tests/Tests.csproj
+++ b/Tests/Tests.csproj
@@ -1,4 +1,4 @@
-
+
netcoreapp2.2
@@ -7,9 +7,12 @@
-
-
-
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+