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
1 change: 1 addition & 0 deletions AngouriMath/Convenience/MathS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Linq.Expressions;
using AngouriMath.Core.FromLinq;
using AngouriMath.Core.TreeAnalysis;
using AngouriMath.Core.TreeAnalysis.Division.RationalDiv;
using AngouriMath.Functions.NumberSystem;

namespace AngouriMath
Expand Down
13 changes: 9 additions & 4 deletions AngouriMath/Core/TreeAnalysis/Additional.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,28 @@ internal static partial class TreeAnalyzer
// TODO: duplication
internal static Entity R() => new VariableEntity("r");

/*
// TODO: realize all methods

/// <summary>
/// Counts all combinations of roots, for example
/// 3 ^ 0.5 + 4 ^ 0.25 will return a set of 8 different numbers
/// </summary>
/// <param name="expr"></param>
/// <returns></returns>
/// TODO: realize all methods
internal static EntitySet EvalAll(Entity expr)
{
/*
var res = new EntitySet();
EvalCombs(expr, res);
return res;
*/
throw new NotImplementedException();
}

internal static void EvalCombs(Entity expr, EntitySet set)
{
throw new NotImplementedException();
/*
if (expr.Name == "Powf" &&
MathS.CanBeEvaluated(expr.Children[1]) &&
MathS.CanBeEvaluated(expr.Children[0]) &&
Expand All @@ -34,7 +39,7 @@ internal static void EvalCombs(Entity expr, EntitySet set)

}
else
set.Add(expr.InnerSimplify());
}*/
set.Add(expr.InnerSimplify());*/
}
}
}
55 changes: 55 additions & 0 deletions AngouriMath/Core/TreeAnalysis/Division/RationalDiv/InfoGatherer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Text;
using AngouriMath.Core.TreeAnalysis.Division.RationalDiv;
using AngouriMath.Functions.Algebra.AnalyticalSolver;

namespace AngouriMath.Core.TreeAnalysis
{
internal static partial class TreeAnalyzer
{
internal static PolyInfo GatherAllPossiblePolynomials(Entity expr)
{
// 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)
{
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));
}

// Gather info about each var as if this var was the only argument of the polynomial P(x)
List<Entity> children;
foreach (var varMentioned in newList)
{
if (expr.entType == Entity.EntType.OPERATOR && expr.Name == "sumf" || expr.Name == "minusf")
children = TreeAnalyzer.LinearChildren(expr, "sumf", "minusf", Const.FuncIfSum);
else
children = new List<Entity> { expr };
res.monoInfo[varMentioned] = PolynomialSolver.GatherMonomialInformation<double>(children, MathS.Var(varMentioned));
}

return res;
}
}
}


namespace AngouriMath.Core.TreeAnalysis.Division.RationalDiv
{
using MonomialInfo = Dictionary<string, Dictionary<double, Entity>>;
using ReplacementInfo = Dictionary<string, Entity>;
internal class PolyInfo
{
internal MonomialInfo monoInfo = new MonomialInfo();
internal ReplacementInfo replacementInfo = new ReplacementInfo();
internal static string NewVarName(string oldName) => oldName + "_r";
internal static string OldVarName(string newName) => newName.Substring(0, newName.Length - 2);
}
}
16 changes: 16 additions & 0 deletions AngouriMath/Core/TreeAnalysis/Search.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,21 @@ 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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -316,10 +316,9 @@ internal static void Solve(Entity expr, VariableEntity x, EntitySet dst)
if (expr == x)
{
dst.Add(0);
return;
} else
{
Entity actualVar = TreeAnalyzer.GetMinimumSubtree(expr, x).Simplify();
Entity actualVar = TreeAnalyzer.GetMinimumSubtree(expr.Simplify(), x);
var res = PolynomialSolver.SolveAsPolynomial(expr, actualVar);

if (res != null)
Expand All @@ -338,7 +337,7 @@ internal static void Solve(Entity expr, VariableEntity x, EntitySet dst)
else
{
EntitySet vars = new EntitySet();
TreeAnalyzer.GetUniqueVariables(expr.Eval() /* otherwise it will count `pi`, `e` as variables */, vars);
TreeAnalyzer.GetUniqueVariables(expr.SubstituteConstants() /* otherwise it will count `pi`, `e` as variables */, vars);
if (vars.Count == 1)
dst.Merge(expr.SolveNt(x));
}
Expand Down
125 changes: 92 additions & 33 deletions AngouriMath/Functions/Algebra/Solver/Analytical/PolynomialSolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,48 @@
using AngouriMath.Core;
using AngouriMath.Core.TreeAnalysis;

namespace AngouriMath.Core.TreeAnalysis
{
internal static partial class TreeAnalyzer
{
/// <summary>
/// That is realized SO badly...
/// TODO
/// </summary>
/// <typeparam name="T"></typeparam>
internal interface IPrimitive<T>
{
void Add(T a);
void Assign(T val);
T GetValue();
}
internal class PrimitiveDouble : IPrimitive<double>
{
private double value = 0;
public void Add(double a) => value += a;
public void Assign(double a) => value = a;
public static implicit operator double(PrimitiveDouble obj) => obj.value;
internal static IPrimitive<double> Create()
{
return new PrimitiveDouble();
}
public double GetValue() => value;
}
internal class PrimitiveInt : IPrimitive<int>
{
private int value = 0;
public void Add(int a) => value += a;
public void Assign(int a) => value = a;
public static implicit operator int(PrimitiveInt obj) => obj.value;
internal static IPrimitive<int> Create()
{
return new PrimitiveInt();
}
public int GetValue() => value;
}
}
}

namespace AngouriMath.Functions.Algebra.AnalyticalSolver
{
internal static class PolynomialSolver
Expand Down Expand Up @@ -38,7 +80,7 @@ private static EntitySet SolveQuadratic(Entity a, Entity b, Entity c)
res.Add((-b + MathS.Sqrt(D)) / (2 * a));
return res;
}

// solves ax3 + bx2 + cx + d
private static EntitySet SolveCubic(Entity a, Entity b, Entity c, Entity d)
{
Expand Down Expand Up @@ -82,6 +124,7 @@ private static EntitySet SolveCubic(Entity a, Entity b, Entity c, Entity d)
{
var beta3 = (-q / 2 - MathS.Sqrt(Q)).Eval();
alpha = alpha.Eval();

beta = beta.Eval();
var p3 = (-p / 3).Eval();
foreach (var root in Number.GetAllRoots(beta3, 3))
Expand Down Expand Up @@ -122,7 +165,7 @@ private static EntitySet SolveCubic(Entity a, Entity b, Entity c, Entity d)
return res;
}
}

// END
// solves hx4 + ax3 + bx2 + cx + d
private static EntitySet SolveQuartic(Entity a, Entity b, Entity c, Entity d, Entity e)
{
Expand All @@ -141,6 +184,7 @@ private static EntitySet SolveQuartic(Entity a, Entity b, Entity c, Entity d, En
if (TreeAnalyzer.IsZero(a))
return SolveCubic(b, c, d, e);


res = new EntitySet();

var alpha = -3 * MathS.Sqr(b) / (8 * MathS.Sqr(a)) + c / a;
Expand All @@ -167,27 +211,6 @@ private static EntitySet SolveQuartic(Entity a, Entity b, Entity c, Entity d, En
return res;
}

internal static Dictionary<int, Entity> GatherMonomialInformation(List<Entity> terms, Entity subtree)
{
var monomialsByPower = new Dictionary<int, Entity>();
// here we fill the dictionary with information about monomials' coefficiants
foreach (var child in terms)
{
Entity free;
int pow;
//{(-1) * (-1) * momo * goose * quack * quack * x * x}
ParseMonomial(subtree, child, out free, out pow);
if (free == null)
return null;
if (!monomialsByPower.ContainsKey(pow))
monomialsByPower[pow] = 0;
monomialsByPower[pow] += free;
}
foreach (var key in monomialsByPower.Keys.ToList())
monomialsByPower[key] = monomialsByPower[key].Simplify();
return monomialsByPower;
}

internal static bool ReduceCommonPower(ref Dictionary<int, Entity> monomials)
{
int commonPower = monomials.Keys.Min();
Expand All @@ -211,7 +234,7 @@ internal static EntitySet SolveAsPolynomial(Entity expr, Entity subtree)
else
children = new List<Entity> { expr };
// Check if all are like {1} * x^n & gather information about them
var monomialsByPower = GatherMonomialInformation(children, subtree);
var monomialsByPower = GatherMonomialInformation<int>(children, subtree);

if (monomialsByPower == null)
return null; // meaning that the given equation is not polynomial
Expand Down Expand Up @@ -280,12 +303,41 @@ Entity GetMonomialByPower(int power)
// Maybe, who knows...
else return null;
}


internal static Dictionary<T, Entity> GatherMonomialInformation<T>(List<Entity> terms, Entity subtree)
{
var monomialsByPower = new Dictionary<T, Entity>();
// here we fill the dictionary with information about monomials' coefficiants
foreach (var child in terms)
{
Entity free;
object pow;
if (typeof(T) == typeof(double))
pow = new TreeAnalyzer.PrimitiveDouble();
else
pow = new TreeAnalyzer.PrimitiveInt();
//{(-1) * (-1) * momo * goose * quack * quack * x * x}
TreeAnalyzer.IPrimitive<T> q = pow as TreeAnalyzer.IPrimitive<T>;
ParseMonomial<T>(subtree, child, out free, ref q);
if (free == null)
return null;
if (!monomialsByPower.ContainsKey(q.GetValue()))
monomialsByPower[q.GetValue()] = 0;
monomialsByPower[q.GetValue()] += free;
}
foreach (var key in monomialsByPower.Keys.ToList())
monomialsByPower[key] = monomialsByPower[key].Simplify();
return monomialsByPower;
}


internal static void ParseMonomial(Entity aVar, Entity expr, out Entity freeMono, out int power)
internal static void ParseMonomial<T>(Entity aVar, Entity expr, out Entity freeMono, ref TreeAnalyzer.IPrimitive<T> power)
{
freeMono = 1; // a * b
power = 0; // x ^ 3
foreach(var mp in TreeAnalyzer.LinearChildren(expr, "mulf", "divf", Const.FuncIfMul))

bool allowFloat = typeof(T) == typeof(double);
foreach (var mp in TreeAnalyzer.LinearChildren(expr, "mulf", "divf", Const.FuncIfMul))
if (mp.entType == Entity.EntType.OPERATOR &&
mp.Name == "powf" &&
mp.Children[0] == aVar)
Expand All @@ -294,31 +346,38 @@ internal static void ParseMonomial(Entity aVar, Entity expr, out Entity freeMono
if (!(mp.Children[1].entType == Entity.EntType.NUMBER))
{
freeMono = null;
power = 0;
return;
}

// x ^ 0.3 is bad
if (!mp.Children[1].GetValue().IsInteger())
if (!allowFloat && !mp.Children[1].GetValue().IsInteger())
{
freeMono = null;
power = 0;
return;
}

power += (int)Math.Round(mp.Children[1].GetValue().Re);
if (allowFloat)
(power as TreeAnalyzer.PrimitiveDouble).Add(mp.Children[1].GetValue().Re);
else
(power as TreeAnalyzer.PrimitiveInt).Add((int)Math.Round(mp.Children[1].GetValue().Re));
}
else if (mp == aVar)
{
power++;
if (allowFloat)
(power as TreeAnalyzer.PrimitiveDouble).Add(1);
else
(power as TreeAnalyzer.PrimitiveInt).Add(1);
}
else
{
// a ^ x, (a + x) etc. are bad
if (mp.FindSubtree(aVar) != null)
{
freeMono = null;
power = 0;
if (allowFloat)
(power as TreeAnalyzer.PrimitiveDouble).Assign(0);
else
(power as TreeAnalyzer.PrimitiveInt).Assign(0);
return;
}
freeMono *= mp;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ internal bool PatternMakeMatch(Pattern pattern, Dictionary<int, Entity> matching
/// <returns></returns>
internal Entity BuildTree(Dictionary<int, Entity> keys)
{
if (!(this.entType == Entity.EntType.PATTERN))
if (this.entType != Entity.EntType.PATTERN)
return this;
if (keys.ContainsKey(PatternNumber))
return keys[PatternNumber];
Expand Down
8 changes: 7 additions & 1 deletion AngouriMath/Functions/Evaluation/Patterns/Patterns.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,10 @@ internal static class Patterns
{ any1 / any2 * any3, any1 * any3 / any2},

// a * {1} / b
{ (const1 * any1) / const2, any1 * (const1 / const2) }
{ (const1 * any1) / const2, any1 * (const1 / const2) },

{ Powf.PHang(Sinf.PHang(any1), Num(2)) - Powf.PHang(Cosf.PHang(any1), Num(2)), -1 * (Powf.PHang(Cosf.PHang(any1), Num(2)) - Powf.PHang(Sinf.PHang(any1), Num(2))) },
{ Powf.PHang(Cosf.PHang(any1), Num(2)) - Powf.PHang(Sinf.PHang(any1), Num(2)), Cosf.PHang(2 * any1) },
};

internal static readonly RuleList ExpandRules = new RuleList
Expand Down Expand Up @@ -272,6 +275,9 @@ internal static class Patterns
{ any1 - any2 * any1, any1 * (Num(1) - any2) },
{ any1 * any2 - any1, any1 * (any2 - Num(1)) },
{ any2 * any1 - any1, any1 * (any2 - Num(1)) },

// a ^ b * c ^ b = (a * c) ^ b
{ Powf.PHang(any1, any2) * Powf.PHang(any3, any2), Powf.PHang(any1 * any3, any2) },
};
}
}
Loading