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

namespace AngouriMath
{
Expand Down Expand Up @@ -230,5 +232,34 @@ public static Entity FromLinq(Expression expr)
var parser = new LinqParser(expr);
return parser.Parse();
}

/// <summary>
/// Returns list of unique variables, for example
/// it extracts `x`, `goose` from (x + 2 * goose) - pi * x
/// </summary>
/// <param name="expr"></param>
/// <returns></returns>
public static EntitySet GetUniqueVariables(Entity expr)
{
var res = new EntitySet();
TreeAnalyzer.GetUniqueVariables(expr, res);
return res;
}

/// <summary>
/// Translates num10 into another number system
/// </summary>
/// <param name="num"></param>
/// <param name="N"></param>
/// <returns></returns>
public static string ToBaseN(double num, int N) => NumberSystem.ToBaseN(num, N);

/// <summary>
/// Translates num into 10 number system
/// </summary>
/// <param name="num"></param>
/// <param name="N"></param>
/// <returns></returns>
public static double FromBaseN(string num, int N) => NumberSystem.FromBaseN(num, N);
}
}
15 changes: 14 additions & 1 deletion AngouriMath/Convenience/SympySyntax.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using AngouriMath.Core.TreeAnalysis;
using AngouriMath.Core;
using AngouriMath.Core.TreeAnalysis;
using System;
using System.Collections.Generic;
using System.Text;
Expand Down Expand Up @@ -90,5 +91,17 @@ public static Entity Diff(Entity expr, params VariableEntity[] vars)
/// <param name="power"></param>
/// <returns></returns>
public static Entity Exp(Entity power) => MathS.Pow(MathS.e, power);

/// <summary>
/// Creates an instance of fraction
/// </summary>
/// <param name="a">
/// Numerator
/// </param>
/// <param name="b">
/// Denominator
/// </param>
/// <returns></returns>
public static Entity Rational(Number a, Number b) => new NumberEntity(a) / new NumberEntity(b);
}
}
4 changes: 2 additions & 2 deletions AngouriMath/Core/FromString/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ internal static Entity Parse(Lexer lexer)
{
throw new ParseException("Empty expression");
}
if (linearExpression[linearExpression.Count - 1].type == Entity.Type.OPERATOR &&
if (linearExpression[linearExpression.Count - 1].entType == Entity.EntType.OPERATOR &&
linearExpression[linearExpression.Count - 1].IsLeaf) //check case `2 + 3 - `
{
throw new ParseException("Expected expression not to end with operator");
Expand All @@ -126,7 +126,7 @@ private static void FindOperator(List<Entity> expr, string op, bool reversed = f
while(i < expr.Count - 1)
{
var id = reversed ? expr.Count - i - 1 : i;
if(expr[id].IsLeaf && expr[id].type == Entity.Type.OPERATOR && op.Contains(expr[id].Name))
if(expr[id].IsLeaf && expr[id].entType == Entity.EntType.OPERATOR && op.Contains(expr[id].Name))
{
expr[id].Children.Add(expr[id - 1]);
expr[id].Children.Add(expr[id + 1]);
Expand Down
27 changes: 14 additions & 13 deletions AngouriMath/Core/Sys/Entity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ public abstract partial class Entity
public string Name = string.Empty;

public bool IsLeaf { get => Children.Count == 0; }
protected Entity(string name, Type type)
/* changed from protected to internal due to protection level of EntType */
internal Entity(string name, EntType type)
{
this.type = type;
this.entType = type;
Children = new List<Entity>();
Name = name;
}
Expand All @@ -35,15 +36,15 @@ protected Entity(string name, Type type)
/// <returns></returns>
public Entity Copy()
{
switch (type)
switch (entType)
{
case Type.NUMBER:
case EntType.NUMBER:
return new NumberEntity((this as NumberEntity).Value);
case Type.VARIABLE:
case EntType.VARIABLE:
return new VariableEntity(Name);
case Type.OPERATOR:
case EntType.OPERATOR:
return new OperatorEntity(Name, Priority);
case Type.FUNCTION:
case EntType.FUNCTION:
return new FunctionEntity(Name);
default:
throw new MathSException("Unknowne entity type");
Expand Down Expand Up @@ -82,9 +83,9 @@ public Entity DeepCopy()
else
return false;
}
if (a.type != b.type)
if (a.entType != b.entType)
return false;
if (a.type == Type.NUMBER && b.type == Type.NUMBER)
if (a.entType == EntType.NUMBER && b.entType == EntType.NUMBER)
return (a as NumberEntity).GetValue() == (b as NumberEntity).GetValue();
if ((a.Name != b.Name) || (a.Children.Count() != b.Children.Count()))
{
Expand All @@ -105,7 +106,7 @@ public Entity DeepCopy()
}
public class NumberEntity : Entity
{
public NumberEntity(Number value) : base(value.ToString(), Type.NUMBER)
public NumberEntity(Number value) : base(value.ToString(), EntType.NUMBER)
{
Priority = Const.PRIOR_NUM;
Value = value;
Expand All @@ -119,17 +120,17 @@ public NumberEntity(Number value) : base(value.ToString(), Type.NUMBER)
}
public class VariableEntity : Entity
{
public VariableEntity(string name) : base(name, Type.VARIABLE) => Priority = Const.PRIOR_VAR;
public VariableEntity(string name) : base(name, EntType.VARIABLE) => Priority = Const.PRIOR_VAR;
public static implicit operator VariableEntity(string name) => new VariableEntity(name);
}
public class OperatorEntity : Entity
{
public OperatorEntity(string name, int priority) : base(name, Type.OPERATOR) {
public OperatorEntity(string name, int priority) : base(name, EntType.OPERATOR) {
Priority = priority;
}
}
public class FunctionEntity : Entity
{
public FunctionEntity(string name) : base(name, Type.FUNCTION) => Priority = Const.PRIOR_FUNC;
public FunctionEntity(string name) : base(name, EntType.FUNCTION) => Priority = Const.PRIOR_FUNC;
}
}
40 changes: 40 additions & 0 deletions AngouriMath/Core/Sys/Number.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,18 @@ public static Number Parse(string s)
return !double.IsNaN(a.Re) && !double.IsNaN(a.Im);
return !(a == b);
}
public static bool operator >(Number a, Number b)
{
if (a.IsComplex() || b.IsComplex())
throw new MathSException("Can't compare complex number with a number");
return a.Re > b.Re;
}
public static bool operator <(Number a, Number b)
{
if (a.IsComplex() || b.IsComplex())
throw new MathSException("Can't compare complex number with a number");
return a.Re < b.Re;
}
public static readonly Number Null = new Number(true);

/// <summary>
Expand All @@ -185,11 +197,39 @@ public bool IsInteger()
{
return !IsComplex() && (Number.IsDoubleZero(Re - Math.Round(Re)));
}
public bool IsNatural()
{
return !IsComplex() && IsInteger() && Re > 0;
}
public static Number Pow(Number a, Number b) => new Number(b.value == 0.5 ? Complex.Sqrt(a.value) : Complex.Pow(a.value, b.value));
public static Number Log(Number a, Number b) => new Number(Complex.Log(a.value, b.Re));
public static Number Sin(Number a) => a.__isReal ? new Number(Math.Sin(a.value.Real)) : new Number(Complex.Sin(a.value));
public static Number Cos(Number a) => a.__isReal ? new Number(Math.Cos(a.value.Real)) : new Number(Complex.Cos(a.value));
public static Number Tan(Number a) => a.__isReal ? new Number(Math.Tan(a.value.Real)) : new Number(Complex.Tan(a.value));

/// <summary>
/// Finds all roots of a number
/// e. g. sqrt(1) = { -1, 1 }
/// root(1, 4) = { -i, i, -1, 1 }
/// </summary>
/// <param name="value"></param>
/// <param name="rootPower"></param>
/// <returns></returns>
public static NumberSet GetAllRoots(Number value, int rootPower)
{
var res = new NumberSet();
Complex val = value.value;
double phi = (Complex.Log(val / Complex.Abs(val)) / MathS.i.value).Real;
double newMod = Math.Pow(Complex.Abs(val), 1.0 / rootPower);
Complex i = new Complex(0, 1);
for (int n = 0; n < rootPower; n++)
{
double newPow = phi / rootPower + 2 * Math.PI * n / rootPower;
res.Add(newMod * Complex.Pow(Math.E, i * newPow));
}
return res;
}

public static Number Cotan(Number a) => a.__isReal ? new Number(1 / Math.Tan(a.value.Real)) : new Number(1 / Complex.Tan(a.value));
public static Number Arcsin(Number a) => a.__isReal ? new Number(Math.Asin(a.value.Real)) : new Number(Complex.Asin(a.value));
public static Number Arccos(Number a) => a.__isReal ? new Number(Math.Acos(a.value.Real)) : new Number(Complex.Acos(a.value));
Expand Down
40 changes: 40 additions & 0 deletions AngouriMath/Core/TreeAnalysis/Additional.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace AngouriMath.Core.TreeAnalysis
{
internal static partial class TreeAnalyzer
{
// TODO: duplication
internal static Entity R() => new VariableEntity("r");

/*
/// <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;
}

internal static void EvalCombs(Entity expr, EntitySet set)
{
if (expr.Name == "Powf" &&
MathS.CanBeEvaluated(expr.Children[1]) &&
MathS.CanBeEvaluated(expr.Children[0]) &&
())
{

}
else
set.Add(expr.InnerSimplify());
}*/
}
}
48 changes: 39 additions & 9 deletions AngouriMath/Core/TreeAnalysis/Search.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AngouriMath.Core.TreeAnalysis
{
public class EntitySet : List<Entity>
{
private HashSet<string> exsts = new HashSet<string>();
private readonly HashSet<string> exsts = new HashSet<string>();
public override string ToString()
{
return "[" + string.Join(", ", this) + "]";
}
public new void Add(Entity ent)
public new void Add(Entity ent) => Add(ent, true);
public void Add(Entity ent, bool check)
{
if (!check)
{
base.Add(ent);
return;
}
if (ent == null)
return;
if (ent.type == Entity.Type.NUMBER && ent.GetValue().IsNull)
if (ent.entType == Entity.EntType.NUMBER && ent.GetValue().IsNull)
return;
ent = ent.SimplifyIntelli();
ent = ent.Simplify();
var hash = ent.ToString();
if (!exsts.Contains(hash))
{
Expand All @@ -35,20 +42,43 @@ public void Merge(IEnumerable<Entity> list)
foreach (var l in list)
Add(l);
}
public EntitySet(params Entity[] entites)
{
foreach (var el in entites)
Add(el);
}
public EntitySet(IEnumerable<Entity> list)
{
foreach (var el in list)
Add(el);
}
// TODO: needs optimization
public static EntitySet operator +(EntitySet set, Entity a) => new EntitySet(set.Select(el => el + a));
public static EntitySet operator -(EntitySet set, Entity a) => new EntitySet(set.Select(el => el - a));
public static EntitySet operator *(EntitySet set, Entity a) => new EntitySet(set.Select(el => el * a));
public static EntitySet operator /(EntitySet set, Entity a) => new EntitySet(set.Select(el => el / a));
public static EntitySet operator +(Entity a, EntitySet set) => new EntitySet(set.Select(el => a + el));
public static EntitySet operator -(Entity a, EntitySet set) => new EntitySet(set.Select(el => a - el));
public static EntitySet operator *(Entity a, EntitySet set) => new EntitySet(set.Select(el => a * el));
public static EntitySet operator /(Entity a, EntitySet set) => new EntitySet(set.Select(el => a / el));
}
internal static partial class TreeAnalyzer
{



internal static void GetUniqueVariables(Entity expr, EntitySet dst)
{
if (expr.type == Entity.Type.VARIABLE)
dst.Add(expr);
// If it is a variable, we will add it
if (expr.entType == Entity.EntType.VARIABLE)
{
// But if it is a constant, we ignore it
if (!MathS.ConstantList.ContainsKey(expr.Name))
dst.Add(expr);
}
else
// Otherwise, we will try to find unique variables from its children
foreach (var child in expr.Children)
GetUniqueVariables(child, dst);
}
internal static bool IsZero(Entity e) => MathS.CanBeEvaluated(e) && e.Eval() == 0;
}
}

Expand Down
6 changes: 3 additions & 3 deletions AngouriMath/Core/TreeAnalysis/Sort.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ public abstract partial class Entity
{
internal string Hash(SortLevel level)
{
if (this.type == Entity.Type.FUNCTION)
if (this.entType == Entity.EntType.FUNCTION)
return this.Name + "_" + string.Join("_", from child in Children select child.Hash(level));
else if (this.type == Type.NUMBER)
else if (this.entType == EntType.NUMBER)
return level == SortLevel.HIGH_LEVEL ? "" : this.Name + " ";
else if (this.type == Entity.Type.VARIABLE)
else if (this.entType == Entity.EntType.VARIABLE)
return "v_" + Name;
else
return (level == SortLevel.LOW_LEVEL ? this.Name + "_" : "") + string.Join("_",
Expand Down
Loading