Skip to content

Commit

Permalink
#224 - Introduce simplification rules
Browse files Browse the repository at this point in the history
  • Loading branch information
sys27 committed Jul 6, 2023
1 parent c2e2cb8 commit 9b1fc56
Show file tree
Hide file tree
Showing 71 changed files with 1,433 additions and 8 deletions.
66 changes: 66 additions & 0 deletions xFunc.Maths/Analyzers2/ChainRuleBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
namespace xFunc.Maths.Analyzers2;

internal class ChainRuleBuilder<TExpression> :
IInitialChainRuleBuilder<TExpression>,
IChainRuleBuilder<TExpression>
where TExpression : IExpression
{
private ChainRule initialRule;
private ChainRule currentRule;

public IChainRuleBuilder<TExpression> WithRule(IRule<TExpression> rule)
{
initialRule = currentRule = new ChainRule(rule);

return this;
}

public IChainRuleBuilder<TExpression> WithNext(IRule<TExpression> next)
{
var chain = new ChainRule(next);
currentRule.SetNext(chain);
currentRule = chain;

return this;
}

public IRule GetRule()
=> initialRule.UnwrapIfEmpty();

private sealed class ChainRule : IRule<TExpression>
{
private readonly IRule<TExpression> current;
private IRule<TExpression>? next;

public ChainRule(IRule<TExpression> rule)
=> current = rule ?? throw new ArgumentNullException(nameof(rule));

public void SetNext(IRule<TExpression> rule)
=> next = rule ?? throw new ArgumentNullException(nameof(rule));

public IRule UnwrapIfEmpty()
=> next is null ? current : this;

public Result Execute(IExpression expression, RuleContext context)
{
var result = current.Execute(expression, context);
if (result.IsHandled() || result.IsReAnalyze())
return result;

if (result.IsContinue())
expression = result.Value;

if (next is not null)
return next.Execute(expression, context);

return Result.NotHandled();
}

public Result Execute(TExpression expression, RuleContext context)
=> Execute(expression as IExpression, context);

public string Name => "Chain Rule";

public string Description => "This is a chain of rules.";
}
}
20 changes: 20 additions & 0 deletions xFunc.Maths/Analyzers2/ExecutionStep.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace xFunc.Maths.Analyzers2;

public readonly struct ExecutionStep
{
public ExecutionStep(IRule rule, IExpression before, IExpression after)
{
Name = rule.Name;
Description = rule.Description;
Before = before;
After = after;
}

public string Name { get; }

public string Description { get; }

public IExpression Before { get; }

public IExpression After { get; }
}
8 changes: 8 additions & 0 deletions xFunc.Maths/Analyzers2/IAnalyzer2.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace xFunc.Maths.Analyzers2;

public interface IAnalyzer2
{
IExpression Analyze(IExpression expression);

IExpression Analyze(IExpression expression, RuleContext context);
}
7 changes: 7 additions & 0 deletions xFunc.Maths/Analyzers2/IChainRuleBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace xFunc.Maths.Analyzers2;

internal interface IChainRuleBuilder<out TExpression>
where TExpression : IExpression
{
IChainRuleBuilder<TExpression> WithNext(IRule<TExpression> next);
}
7 changes: 7 additions & 0 deletions xFunc.Maths/Analyzers2/IInitialChainRuleBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace xFunc.Maths.Analyzers2;

internal interface IInitialChainRuleBuilder<out TExpression>
where TExpression : IExpression
{
IChainRuleBuilder<TExpression> WithRule(IRule<TExpression> rule);
}
10 changes: 10 additions & 0 deletions xFunc.Maths/Analyzers2/IRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace xFunc.Maths.Analyzers2;

public interface IRule
{
Result Execute(IExpression expression, RuleContext context);

string Name { get; }

string Description { get; }
}
6 changes: 6 additions & 0 deletions xFunc.Maths/Analyzers2/IRule{TExpression}.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace xFunc.Maths.Analyzers2;

public interface IRule<in TExpression> : IRule
{
Result Execute(TExpression expression, RuleContext context);
}
41 changes: 41 additions & 0 deletions xFunc.Maths/Analyzers2/Result.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
namespace xFunc.Maths.Analyzers2;

public readonly struct Result
{
private readonly ResultKind kind;

private Result(ResultKind kind, IExpression? value)
{
this.kind = kind;
Value = value;
}

public static Result NotHandled()
=> new Result(ResultKind.NotHandled, default);

public static Result Handled(IExpression value)
=> new Result(ResultKind.Handled, value);

public static Result Continue(IExpression value)
=> new Result(ResultKind.Continue, value);

public static Result ReAnalyze(IExpression value)
=> new Result(ResultKind.ReAnalyze, value);

private bool IsKind(ResultKind kind)
=> this.kind == kind;

public bool IsNotHandled()
=> IsKind(ResultKind.NotHandled);

public bool IsHandled()
=> IsKind(ResultKind.Handled);

public bool IsContinue()
=> IsKind(ResultKind.Continue);

public bool IsReAnalyze()
=> IsKind(ResultKind.ReAnalyze);

public IExpression? Value { get; }
}
9 changes: 9 additions & 0 deletions xFunc.Maths/Analyzers2/ResultKind.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace xFunc.Maths.Analyzers2;

public enum ResultKind
{
NotHandled,
Handled,
Continue,
ReAnalyze,
}
35 changes: 35 additions & 0 deletions xFunc.Maths/Analyzers2/Rule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace xFunc.Maths.Analyzers2;

public abstract class Rule<TExpression> : IRule<TExpression>
where TExpression : IExpression
{
Result IRule.Execute(IExpression expression, RuleContext context)
=> Execute((TExpression)expression, context);

public Result Execute(TExpression expression, RuleContext context)
{
var result = ExecuteInternal(expression, context);
if (result.IsHandled() || result.IsContinue() || result.IsReAnalyze())
context.AddStep(this, expression, result.Value);

return result;
}

protected abstract Result ExecuteInternal(TExpression expression, RuleContext context);

protected static Result Handled(IExpression value)
=> Result.Handled(value);

protected static Result Continue(IExpression value)
=> Result.Continue(value);

protected static Result ReAnalyze(IExpression value)
=> Result.ReAnalyze(value);

protected static Result NotHandled()
=> Result.NotHandled();

public virtual string Name => GetType().Name;

public abstract string Description { get; }
}
21 changes: 21 additions & 0 deletions xFunc.Maths/Analyzers2/RuleContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace xFunc.Maths.Analyzers2;

public class RuleContext
{
private readonly IAnalyzer2 analyzer;
private readonly List<ExecutionStep> steps;

public RuleContext(IAnalyzer2 analyzer)
{
this.analyzer = analyzer;
this.steps = new List<ExecutionStep>();
}

public IExpression Analyze(IExpression expression)
=> analyzer.Analyze(expression, this);

public void AddStep(IRule rule, IExpression before, IExpression after)
=> steps.Add(new ExecutionStep(rule, before, after));

public IEnumerable<ExecutionStep> Steps => steps;
}
16 changes: 16 additions & 0 deletions xFunc.Maths/Analyzers2/RuleStorage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace xFunc.Maths.Analyzers2;

internal class RuleStorage
{
private readonly IDictionary<Type, IRule> rules;

public RuleStorage(IDictionary<Type, IRule> rules)
=> this.rules = rules;

public IRule? GetRule(Type type)
{
rules.TryGetValue(type, out var rule);

return rule;
}
}
29 changes: 29 additions & 0 deletions xFunc.Maths/Analyzers2/RuleStorageBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace xFunc.Maths.Analyzers2;

internal class RuleStorageBuilder
{
private readonly IDictionary<Type, IRule> rules = new Dictionary<Type, IRule>();

public RuleStorageBuilder WithRule<TExpression>(IRule<TExpression> rule)
where TExpression : IExpression
{
rules[typeof(TExpression)] = rule;

return this;
}

public RuleStorageBuilder WithChain<TExpression>(
Action<IInitialChainRuleBuilder<TExpression>> builder)
where TExpression : IExpression
{
var ruleBuilder = new ChainRuleBuilder<TExpression>();
builder(ruleBuilder);
var rule = ruleBuilder.GetRule();
rules[typeof(TExpression)] = rule;

return this;
}

public RuleStorage Build()
=> new RuleStorage(rules);
}
15 changes: 15 additions & 0 deletions xFunc.Maths/Analyzers2/Rules/AbsRules/AbsNestedRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace xFunc.Maths.Analyzers2.Rules.AbsRules;

public class AbsNestedRule : Rule<Abs>
{
protected override Result ExecuteInternal(Abs expression, RuleContext context)
=> expression.Argument switch
{
Abs abs => Handled(abs),
_ => NotHandled(),
};

public override string Name => "Abs Nested Rule";

public override string Description => "";
}
15 changes: 15 additions & 0 deletions xFunc.Maths/Analyzers2/Rules/AbsRules/AbsUnaryMinusRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace xFunc.Maths.Analyzers2.Rules.AbsRules;

public class AbsUnaryMinusRule : Rule<Abs>
{
protected override Result ExecuteInternal(Abs expression, RuleContext context)
=> expression.Argument switch
{
UnaryMinus minus => Handled(minus.Argument),
_ => NotHandled(),
};

public override string Name => "Abs Unary Minus";

public override string Description => "";
}
11 changes: 11 additions & 0 deletions xFunc.Maths/Analyzers2/Rules/AbsRules/AbsUnaryRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace xFunc.Maths.Analyzers2.Rules.AbsRules;

public class AbsUnaryRule : UnaryRule<Abs>
{
protected override Abs Create(IExpression argument)
=> new Abs(argument);

public override string Name => "Abs Unary Rule";

public override string Description => "";
}
11 changes: 11 additions & 0 deletions xFunc.Maths/Analyzers2/Rules/AddRules/AddBinaryRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace xFunc.Maths.Analyzers2.Rules.AddRules;

public class AddBinaryRule : BinaryRule<Add>
{
protected override Add Create(IExpression left, IExpression right)
=> new Add(left, right);

public override string Name => "Add Binary Rule";

public override string Description => "";
}
21 changes: 21 additions & 0 deletions xFunc.Maths/Analyzers2/Rules/AddRules/AddConstAngle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace xFunc.Maths.Analyzers2.Rules.AddRules;

public class AddConstAngle : Rule<Add>
{
protected override Result ExecuteInternal(Add expression, RuleContext context)
=> expression switch
{
(Number left, Angle right)
=> Handled((left.Value + right.Value).AsExpression()),
(Angle left, Number right)
=> Handled((left.Value + right.Value).AsExpression()),
(Angle left, Angle right)
=> Handled((left.Value + right.Value).AsExpression()),

_ => NotHandled(),
};

public override string Name => "Add Angle Constants";

public override string Description => "";
}
Loading

0 comments on commit 9b1fc56

Please sign in to comment.