Skip to content

Commit

Permalink
Ground work for solving has been laid (#30)
Browse files Browse the repository at this point in the history
* Added method to Node

* Moved trig simplification up a stage

* Cot and Tan simplifications

cos(x)/sin(x) -> cot(x)
sin(x)/cos(x) -> tan(x)

* Optimized Generate function

New function avoids an allocation and goes from
O(n^2) to O(n)

* Another cot rule

[f(x) * cos(x)]/sin(x) -> f(x) * cot(x)

* Rewriting derivative rule descriptions

* In depth derivative assistance

* Misc change

* Updated ToPostFix

Removed recursion in favor of an explicit stack

* New trig transformations

5 trig transformations added

* Refactored Unit Tests

* Added method studs

Made derive an internal function

* Groundwork for normalization

* Compressing and expanding functions working

* Normalization WIP

* Even Trig Identities

* Misc push

* Misc Refactor of Node

* Odd Trig Identities

* Misc refactor of AST

* Added more use of SetRoot

Removed Alias

* Misc changes

* Misc Changes

* Added expansion for internal_product

* Additional simplifications

* Added internal_product functionality

* Synced up most of the rules in InternalSwap and Swap

* Tree based generation for gen function

* Normalize Refactor

* Removed uneeded clones

* Simplified Case Logic for Mixed divison and multiplication

* Reduced uneeded allocations in normal mode

* Update AbMath.dll

* Better time tracking

* Added an feature flag

The flag Implicit Multiplication Priority determines if 1/2x is
grouped as 1/(2x) when on and (1/2)x when off.

* Better tracking of TotalMilliseconds

* Tokenizer changes

* Alias changes

* derivative can be called multiple times in one call

* Some Algebra added

* Misc changes

* Restricted when GCD Simplifications can be used

* Infinite Optimization Chains generic guard

* Division simplifications added

* Added power reduction and some solver methods

* Solver Multiplication

* Added a total command that replaces sum

The sum command will be reimplemented to represent a different concept

* Removed a rule that conflicts with another rule

This resulted in an infinite loop

* Added a restriction to subtraction operator

* Subtraction rule cannot trigger when a division is present

* Added support for subtraction of division in AST

* Made Derive nonrecursive

* Made simplifications itterative

* Small changes

* Misc

* Added restrictions to ensure that trig functions don't violate domain boundaries

Previously a function like sin(1/x)^2 + cos(1/x)^2 would equal 1 even when x = 0. This is unintended behavious and should be avoided at all costs?

* Added a cos over sin rule

* Fixes #29

Fixed #29 and added a test case for it
  • Loading branch information
65001 authored Oct 30, 2019
1 parent 29b7290 commit 3d28dd2
Show file tree
Hide file tree
Showing 24 changed files with 3,825 additions and 2,620 deletions.
5 changes: 5 additions & 0 deletions AbMath/AbMath.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<Copyright>(C) Abhishek Sathiabalan. 2018.</Copyright>
<PackageReleaseNotes />
<PackageTags>reverse polish notation, rpn, shunting yard, calculator, library</PackageTags>
<LangVersion>default</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand All @@ -25,6 +26,10 @@
<None Remove="CLI Table\**" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.3" />
</ItemGroup>

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="xcopy &quot;$(ProjectDir)\bin\Release\netstandard2.0\AbMath.dll&quot; &quot;$(ProjectDir)\AbMath.dll&quot; /Y" />
</Target>
Expand Down
Binary file modified AbMath/AbMath.dll
Binary file not shown.
3,277 changes: 2,321 additions & 956 deletions AbMath/Calculator/AST.cs

Large diffs are not rendered by default.

149 changes: 72 additions & 77 deletions AbMath/Calculator/Data.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,16 @@ public class DataStore
{
private readonly List<string> _meta_functions;

private readonly Dictionary<string,Function> _functions;
private readonly Dictionary<string,Operator> _operators;
private readonly Dictionary<string, Function> _functions;
private readonly Dictionary<string, Operator> _operators;

private readonly Dictionary<string, string> _aliases;

private readonly Dictionary<double, string> _autoFormat;

private readonly List<string> _leftbracket;
private readonly List<string> _rightbracket;

private List<TimeRecord> _time;
private readonly Dictionary<string, string> _variableStore;

Expand Down Expand Up @@ -91,8 +92,8 @@ public class DataStore
public bool ContainsEquation =>
Equation.Contains("=") || Equation.Contains(">") || Equation.Contains("<") ;

public double TotalMilliseconds => this.Time.Sum(t => t.ElapsedMilliseconds);
public double TotalSteps => this.Time.Sum(t => t.ElapsedTicks);
public double TotalMilliseconds => this.Time.Where(t => !t.Type.Contains(".")).Sum(t => t.ElapsedMilliseconds);
public double TotalSteps => this.Time.Where(t => !t.Type.Contains(".")).Sum(t => t.ElapsedTicks);

#region Config
/// <summary>
Expand All @@ -110,23 +111,12 @@ public class DataStore
public bool DebugMode;

/// <summary>
/// This type of optimization can remove some
/// variables entirely or combine them to optimize
/// the calculation over many iterations.
/// These optimizations cannot optimize across a grouping symbols.
/// </summary>
public bool PreOptimization = true;

/// <summary>
/// This type of optimizations can remove
/// variables entirely or combine them to
/// optimize the calculations over many iterations.
/// Log simplification rules and other similar rules are implemented
/// here.
/// These optimizations happen on the Reverse Polish Notation and
/// hence can optimize across a traditional grouping symbol.
/// Implicit multiplication in some interpretations
/// of order of operations has a higher priority
/// compared to that of division.
/// Set this to true to enable that feature.
/// </summary>
public bool PostOptimization = true;
public bool ImplicitMultiplicationPriority;
#endregion


Expand All @@ -145,15 +135,15 @@ public DataStore(string equation)
_aliases = new Dictionary<string, string>();
_autoFormat = new Dictionary<double, string>();

_leftbracket = new List<string>();
_rightbracket = new List<string>();
_leftbracket = new List<string>() { "(", "{", "[" };
_rightbracket = new List<string>() { ")", "}", "]", "," };

_time = new List<TimeRecord>(4);
_variableStore = new Dictionary<string, string>();

DefaultFunctions();
DefaultOperators();
DefaultAliases();
DefaultBrackets();
DefaultFormats();
}

Expand All @@ -173,7 +163,8 @@ public void AddTimeRecord(string type, Stopwatch stopwatch)
{
ElapsedMilliseconds = stopwatch.ElapsedMilliseconds,
ElapsedTicks = stopwatch.ElapsedTicks,
Type = type
Type = type,
Count = 1
});
}

Expand All @@ -182,17 +173,24 @@ public void AddTimeRecord(TimeRecord time)
if (_time.Count > 0 && _time[_time.Count - 1].Type == time.Type)
{
TimeRecord prev = _time[_time.Count - 1];

prev.ElapsedMilliseconds += time.ElapsedMilliseconds;
prev.ElapsedTicks += time.ElapsedTicks;
prev.Count += 1;

_time[_time.Count - 1] = prev;
}
//If a Type contains a period it denotes that it should always be merged.
else if (time.Type.Contains(".") && _time.Any(t => t.Type == time.Type) )
{
TimeRecord prev = _time.Find(t => t.Type == time.Type);
int index = _time.FindIndex(t => t.Type == time.Type);
TimeRecord prev = _time[index];

prev.ElapsedMilliseconds += time.ElapsedMilliseconds;
prev.ElapsedTicks += time.ElapsedTicks;
//_time.Add(time);
prev.Count += 1;

_time[index] = prev;
}
else
{
Expand All @@ -209,7 +207,9 @@ public Tables<string> TimeRecords()
});

times.Add(new Schema() { Column = "Type", Width = 30 });
times.Add(new Schema() {Column = "# Calls", Width = 8});
times.Add(new Schema() { Column = "Time (ms)", Width = 10 });

times.Add(new Schema() { Column = "Ticks", Width = 8 });
times.Add(new Schema() { Column = "% Milliseconds", Width = 16 });
times.Add(new Schema() { Column = "% Ticks", Width = 9 });
Expand All @@ -223,18 +223,21 @@ public Tables<string> TimeRecords()

times.Add(new string[]
{
TR.Type, TR.ElapsedMilliseconds.ToString(), TR.ElapsedTicks.ToString("N0"),
TR.Type,
TR.Count.ToString(),
TR.ElapsedMilliseconds.ToString(),
TR.ElapsedTicks.ToString("N0"),
Math.Round((100 * TR.ElapsedMilliseconds / miliseconds), 2).ToString(),
(100 * TR.ElapsedTicks / steps).ToString("N0")
});
}

times.Add(new string[]
{
"Total", miliseconds.ToString("N0") , steps.ToString("N0"), " ", " "
"Total", "", miliseconds.ToString("N0") , steps.ToString("N0"), " ", " "
});

times.Add(new string[] {Equation, "", "", "", "" });
times.Add(new string[] {Equation, "", "", "", "", "" });

return times;
}
Expand All @@ -243,12 +246,22 @@ public void AddLeftBracket(string value)
{
_leftbracket.Add(value);
}

public void AddLeftBracket(string[] value)
{
_leftbracket.AddRange(value);
}

public void AddRightBracket(string value)
{
_rightbracket.Add(value);
}

public void AddRightBracket(string[] value)
{
_rightbracket.AddRange(value);
}

public void AddAlias(string key, string value)
{
_aliases.Add(key, value);
Expand All @@ -269,6 +282,11 @@ public void AddFunction(string key, Function func)
_functions.Add(key, func);
}

public void RemoveFunction(string function)
{
_functions.Remove(function);
}

public void AddOperator(string key, Operator ops)
{
_operators.Add(key, ops);
Expand All @@ -284,11 +302,6 @@ public bool IsOperator(string value)
return Operators.ContainsKey(value);
}

public bool IsOperator(Token token)
{
return token.Type == Type.Operator;
}

public bool IsUnary(string value)
{
return IsOperator(value) && (value == "-" || value == "−" || value == "+");
Expand All @@ -306,7 +319,7 @@ public bool IsFunction(string value)

public bool IsVariable(string value)
{
return value != "." && !(IsNumber(value) || IsOperator(value) || IsFunction(value) || IsLeftBracket(value) || IsRightBracket(value));
return value != "." && !(IsOperator(value) || IsFunction(value) || IsLeftBracket(value) || IsRightBracket(value) || IsNumber(value));
}

public bool IsLeftBracket(string value)
Expand All @@ -332,8 +345,8 @@ public Type Resolve(string value)
private void DefaultAliases()
{
AddAlias("÷", "/");
AddAlias("Γ","gamma");
AddAlias("π", "pi");
AddAlias("gamma", ");
AddAlias("pi",");
AddAlias("≠", "!=");
AddAlias("≥", ">=");
AddAlias("≤", "<=");
Expand All @@ -347,35 +360,10 @@ private void DefaultAliases()
AddAlias("-infinity", "-∞");
}

private void DefaultBrackets()
{
AddLeftBracket("(");
AddLeftBracket("{");
AddLeftBracket("[");

AddRightBracket(")");
AddRightBracket("}");
AddRightBracket("]");
AddRightBracket(",");
}

private void DefaultOperators()
{
AddOperator("^", new Operator
{
Assoc = Assoc.Right,
Weight = 5,
Arguments = 2,
Compute = DoOperators.Power
});

AddOperator("E", new Operator
{
Assoc = Assoc.Right,
Weight = 5,
Arguments = 2,
Compute = DoOperators.E
});
AddOperator("^", new Operator(Assoc.Right, 5, 2, DoOperators.Power));
AddOperator("E", new Operator(Assoc.Right, 5, 2, DoOperators.E));

AddOperator("!", new Operator
{
Expand Down Expand Up @@ -698,7 +686,7 @@ private void DefaultFunctions()
});

#region Constants
AddFunction("pi", new Function
AddFunction("π", new Function
{
Arguments = 0,
MinArguments = 0,
Expand All @@ -724,7 +712,7 @@ private void DefaultFunctions()
}
);

AddFunction("sum", new Function()
AddFunction("total", new Function()
{
Arguments = 1,
MinArguments = 1,
Expand All @@ -733,6 +721,13 @@ private void DefaultFunctions()
}
);

AddFunction("sum", new Function()
{
Arguments = 1,
MinArguments = 4,
MaxArguments = 5
});

AddFunction("avg", new Function()
{
Arguments = 1,
Expand Down Expand Up @@ -774,7 +769,7 @@ private void DefaultFunctions()
MinArguments = 1
});

AddFunction("gamma", new Function()
AddFunction("Γ", new Function()
{
Arguments = 1,
Compute = DoFunctions.Gamma,
Expand All @@ -788,18 +783,9 @@ private void DefaultFunctions()
{
Arguments = 2,
MinArguments = 2,
MaxArguments = 2,
});

//
AddFunction("derive", new Function
{
Arguments = 1,
MaxArguments = 1,
MinArguments = 1
MaxArguments = 3,
});


AddFunction("integrate", new Function()
{
Arguments = 4,
Expand All @@ -815,6 +801,13 @@ private void DefaultFunctions()
MaxArguments = 5
});

AddFunction("solve", new Function()
{
Arguments = 2,
MinArguments = 2,
MaxArguments = 3
});

/*
AddFunction("plot", new Function()
{
Expand All @@ -828,6 +821,8 @@ private void DefaultFunctions()
_meta_functions.Add("integrate");
_meta_functions.Add("table");
_meta_functions.Add("plot");
_meta_functions.Add("solve");
_meta_functions.Add("sum");
#endregion
}
private void DefaultFormats()
Expand Down
Loading

0 comments on commit 3d28dd2

Please sign in to comment.