Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AngouriMath/Convenience/MathS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ namespace AngouriMath

public static partial class MathS
{
public static Entity QuackQuack(Entity p, Entity q) => TreeAnalyzer.DividePolynoms(p, q);

/// <summary>
/// https://en.wikipedia.org/wiki/Trigonometric_functions
/// </summary>
Expand Down
28 changes: 21 additions & 7 deletions AngouriMath/Core/TreeAnalysis/Division/RationalDiv/InfoGatherer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,34 @@ namespace AngouriMath.Core.TreeAnalysis
{
internal static partial class TreeAnalyzer
{
internal static PolyInfo GatherAllPossiblePolynomials(Entity expr)
internal static PolyInfo GatherAllPossiblePolynomials(Entity expr, bool replaceVars)
{
// TODO: refactor

expr = expr.DeepCopy();

// Init
var res = new PolyInfo();
var mentionedVarList = MathS.GetUniqueVariables(expr);
var newList = new List<string>();

// Replace all variables we can
foreach (var varMentioned in mentionedVarList)
if (replaceVars)
{
// Replace all variables we can
foreach (var varMentioned in mentionedVarList)
{
var replacement = TreeAnalyzer.GetMinimumSubtree(expr, varMentioned);
res.replacementInfo[varMentioned.Name] = replacement;
FindAndReplace(ref expr, replacement, new VariableEntity(PolyInfo.NewVarName(varMentioned.Name)));
newList.Add(PolyInfo.NewVarName(varMentioned.Name));
}
}
else
{
var replacement = TreeAnalyzer.GetMinimumSubtree(expr, varMentioned);
res.replacementInfo[varMentioned.Name] = replacement;
expr = expr.FindAndReplace(replacement, new VariableEntity(PolyInfo.NewVarName(varMentioned.Name)));
newList.Add(PolyInfo.NewVarName(varMentioned.Name));
foreach(var v in mentionedVarList)
{
newList.Add(v.Name);
}
}

// Gather info about each var as if this var was the only argument of the polynomial P(x)
Expand Down
31 changes: 15 additions & 16 deletions AngouriMath/Core/TreeAnalysis/Search.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,21 @@ internal static void GetUniqueVariables(Entity expr, EntitySet dst)
GetUniqueVariables(child, dst);
}
internal static bool IsZero(Entity e) => MathS.CanBeEvaluated(e) && e.Eval() == 0;

internal static void FindAndReplace(ref Entity originTree, Entity oldSubtree, Entity newSubtree)
{
if (originTree == oldSubtree)
{
originTree = newSubtree;
return;
}
for (int i = 0; i < originTree.Children.Count; i++)
{
var child = originTree.Children[i];
FindAndReplace(ref child, oldSubtree, newSubtree);
originTree.Children[i] = child;
}
}
}
}

Expand All @@ -103,21 +118,5 @@ public Entity FindSubtree(Entity subtree)
}
return null;
}

/// <summary>
/// Replaces all occurances of oldTree with newTree, e. g.
/// (x * 2 + 3 / (x * 2)).FindAndReplace(x * 2, y) => y + 3 / y
/// </summary>
/// <param name="oldTree"></param>
/// <param name="newTree"></param>
/// <returns></returns>
public Entity FindAndReplace(Entity oldTree, Entity newTree)
{
if (this == oldTree)
return newTree;
for (int i = 0; i < Children.Count; i++)
Children[i] = Children[i].FindAndReplace(oldTree, newTree);
return this;
}
}
}
105 changes: 105 additions & 0 deletions AngouriMath/Core/TreeAnalysis/TreeDivision.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using AngouriMath.Core.TreeAnalysis.Division.RationalDiv;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AngouriMath.Core.TreeAnalysis
{
internal static partial class TreeAnalyzer
{
internal static Entity DividePolynoms(Entity p, Entity q)
{
// Entity expr = "sqrt(x) * sin(y) + a ^ (-1) * x * 5 - x ^ 3 * sin(y) ^ 0.2 - 2 + a ^ 4";
// ---> (x^0.6 + 2x^0.3 + 1) / (x^0.3 + 1)
var replacementInfo = GatherAllPossiblePolynomials(p + q, replaceVars: true).replacementInfo;

foreach (var pair in replacementInfo)
{
FindAndReplace(ref p, pair.Value, new VariableEntity(PolyInfo.NewVarName(pair.Key)));
FindAndReplace(ref q, pair.Value, new VariableEntity(PolyInfo.NewVarName(pair.Key)));
}

var monoinfoQ = GatherAllPossiblePolynomials(q, replaceVars: false).monoInfo;
var monoinfoP = GatherAllPossiblePolynomials(p, replaceVars: false).monoInfo;

var originalP = p;
var originalQ = q;

// TODO remove extra copy
p = p.DeepCopy();
q = q.DeepCopy();

string polyvar = null;

// TODO use Linq to find polyvar
foreach(var pair in monoinfoQ)
{
if(pair.Value != null && monoinfoP[pair.Key] != null)
{
polyvar = pair.Key;
break;
}
}

// cannot divide, return unchanged
if (string.IsNullOrEmpty(polyvar)) return originalP / originalQ;

var maxpowQ = monoinfoQ[polyvar].Keys.Max();
var maxpowP = monoinfoP[polyvar].Keys.Max();
var maxvalQ = monoinfoQ[polyvar][maxpowQ];
var maxvalP = monoinfoP[polyvar][maxpowP];

var result = new Dictionary<double, Entity>();

// TODO: add case where all powers are non-positive
// for now just return polynomials unchanged
if (maxpowP < maxpowQ) return originalP / originalQ;

// possibly very long process
while (maxpowP >= maxpowQ)
{
// KeyPair is ax^n with Key=n, Value=a
double deltapow = maxpowP - maxpowQ;
Entity deltamul = maxvalP / maxvalQ;
result[deltapow] = deltamul;

foreach (var n in monoinfoQ[polyvar])
{
// TODO: precision loss can happen here. MUST be fixed somehow
double newpow = deltapow + n.Key;
if (!monoinfoP[polyvar].ContainsKey(newpow))
{
monoinfoP[polyvar][newpow] = -deltamul * n.Value;
}
else
{
monoinfoP[polyvar][newpow] -= deltamul * n.Value;
if (monoinfoP[polyvar][newpow] == 0)
monoinfoP[polyvar].Remove(newpow);
}
monoinfoP[polyvar][newpow] = monoinfoP[polyvar][newpow].SimplifyIntelli();
}
if (monoinfoP[polyvar].ContainsKey(maxpowP))
monoinfoP[polyvar].Remove(maxpowP);

maxpowQ = monoinfoQ[polyvar].Keys.Max();
maxpowP = monoinfoP[polyvar].Keys.Max();
maxvalQ = monoinfoQ[polyvar][maxpowQ];
maxvalP = monoinfoP[polyvar][maxpowP];
}

Entity res = new Number(0);
foreach(var pair in result)
{
res += pair.Value * MathS.Pow(new VariableEntity(polyvar), pair.Key);
}
// TODO: we know that variable is the same but with suffux '_r'. This foreach loop can be speeded-up
foreach (var subst in replacementInfo)
{
FindAndReplace(ref res, new VariableEntity(PolyInfo.NewVarName(subst.Key)), subst.Value);
}
return res.SimplifyIntelli();
}
}
}
9 changes: 9 additions & 0 deletions Samples/Samples/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,15 @@ static Complex MyFunc(Complex x)

static void Main(string[] _)
{
//Entity e1 = "x^5 + 9 x^4 + 8 x^3 - 33 x^2 + 25 x - 6";
//Entity e2 = "x ^2 + 3x - 2";

Entity e1 = "(sin(x) * y + 2 * sin(x)^2 * y^2 - 1)*(cos(x)^2 * y - cos(x)^3 * y^3 + 2)";
e1 = e1.Expand().SimplifyIntelli();
Entity e2 = "(cos(x)^2 * y - cos(x)^3 * y^3 + 2)";
Console.WriteLine(">> ({0}) / ({1})", e1, e2);
Console.WriteLine();
Console.WriteLine(MathS.QuackQuack(e1, e2));
//Entity expr = "(x - 2)(x - 3)(x - i)";
//Entity expr = "(2x + y) / (x + 0.5y)";
//Console.WriteLine(expr.Solve("x"));
Expand Down