Skip to content

Commit

Permalink
Close #324 - Dictionary as parameters storage
Browse files Browse the repository at this point in the history
  • Loading branch information
sys27 committed Sep 17, 2020
1 parent 403d921 commit 85369cf
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 257 deletions.
2 changes: 1 addition & 1 deletion xFunc.Benchmark/Benchmarks/ProcessorBenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ public IExpression Parse()

[Benchmark]
public NumberResult Solve()
=> processor.Solve<NumberResult>("count(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + (2 * sin(4 * cos(6 * tan(8 * cot(pi) ^ 2) ^ 3) ^ 4) ^ 5 + 2 * sin(4 * cos(6 * tan(8 * cot(pi) ^ 2) ^ 3) ^ 4) ^ 5 + 2 * sin(4 * cos(6 * tan(8 * cot(pi) ^ 2) ^ 3) ^ 4) ^ 5 + 2 * sin(4 * cos(6 * tan(8 * cot(pi) ^ 2) ^ 3) ^ 4) ^ 5) * 10 ^ 6 + 10!");
=> processor.Solve<NumberResult>("count(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + (2 * sin(4 * cos(6 * tan(8 * cot(pi / 4) ^ 2) ^ 3) ^ 4) ^ 5 + 2 * sin(4 * cos(6 * tan(8 * cot(pi / 4) ^ 2) ^ 3) ^ 4) ^ 5 + 2 * sin(4 * cos(6 * tan(8 * cot(pi / 4) ^ 2) ^ 3) ^ 4) ^ 5 + 2 * sin(4 * cos(6 * tan(8 * cot(pi / 4) ^ 2) ^ 3) ^ 4) ^ 5) * 10 ^ 6 + 10!");
}
}
8 changes: 4 additions & 4 deletions xFunc.Maths/Expressions/Collections/FunctionCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Runtime.Serialization;
Expand Down Expand Up @@ -46,6 +47,7 @@ public FunctionCollection()
/// </summary>
/// <param name="info">The info.</param>
/// <param name="context">The context.</param>
[ExcludeFromCodeCoverage]
protected FunctionCollection(SerializationInfo info, StreamingContext context)
: base(info, context)
{
Expand Down Expand Up @@ -77,9 +79,7 @@ protected FunctionCollection(SerializationInfo info, StreamingContext context)
/// </summary>
/// <param name="args">The <see cref="NotifyCollectionChangedEventArgs"/> instance containing the event data.</param>
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
{
CollectionChanged?.Invoke(this, args);
}
=> CollectionChanged?.Invoke(this, args);

/// <summary>
/// Adds new function.
Expand Down Expand Up @@ -109,7 +109,7 @@ public new void Remove(UserFunction key)
/// <param name="function">The function.</param>
/// <returns>An user function.</returns>
/// <exception cref="KeyNotFoundException">The exception that is thrown when the key specified for accessing an element in a collection does not match any key in the collection.</exception>
public UserFunction GetKeyByKey(UserFunction function)
public UserFunction GetKey(UserFunction function)
{
var func = Keys.FirstOrDefault(uf => uf.Equals(function));
if (func == null)
Expand Down
165 changes: 52 additions & 113 deletions xFunc.Maths/Expressions/Collections/ParameterCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Numerics;
using xFunc.Maths.Expressions.Angles;
using xFunc.Maths.Resources;
Expand All @@ -30,8 +29,8 @@ namespace xFunc.Maths.Expressions.Collections
/// </summary>
public class ParameterCollection : IEnumerable<Parameter>, INotifyCollectionChanged
{
private readonly HashSet<Parameter> constants;
private readonly HashSet<Parameter> collection;
private readonly Dictionary<string, Parameter> constants;
private readonly Dictionary<string, Parameter> collection;

/// <summary>
/// Occurs when the collection changes.
Expand All @@ -51,7 +50,7 @@ public ParameterCollection()
/// </summary>
/// <param name="initConstants">if set to <c>true</c> initialize constants.</param>
public ParameterCollection(bool initConstants)
: this(Enumerable.Empty<Parameter>(), initConstants)
: this(Array.Empty<Parameter>(), initConstants)
{
}

Expand All @@ -64,15 +63,29 @@ public ParameterCollection(IEnumerable<Parameter> parameters)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ParameterCollection"/> class.
/// </summary>
/// <param name="parameters">The parameters.</param>
public ParameterCollection(ParameterCollection parameters)
: this(parameters?.collection.Values, true)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ParameterCollection" /> class.
/// </summary>
/// <param name="parameters">The parameters.</param>
/// <param name="initConstants">if set to <c>true</c> initialize constants.</param>
public ParameterCollection(IEnumerable<Parameter> parameters, bool initConstants)
public ParameterCollection(IEnumerable<Parameter>? parameters, bool initConstants)
{
constants = new HashSet<Parameter>();
collection = new HashSet<Parameter>(parameters);
if (parameters == null)
throw new ArgumentNullException(nameof(parameters));

constants = new Dictionary<string, Parameter>();
collection = new Dictionary<string, Parameter>();
foreach (var item in parameters)
collection.Add(item.Key, item);

if (initConstants)
InitializeConstants();
Expand All @@ -83,26 +96,24 @@ public ParameterCollection(IEnumerable<Parameter> parameters, bool initConstants
/// </summary>
/// <param name="args">The <see cref="NotifyCollectionChangedEventArgs"/> instance containing the event data.</param>
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
{
CollectionChanged?.Invoke(this, args);
}
=> CollectionChanged?.Invoke(this, args);

private void InitializeConstants()
{
constants.Add(Parameter.CreateConstant("π", AngleValue.Radian(Math.PI))); // Archimedes' constant
constants.Add(Parameter.CreateConstant("pi", AngleValue.Radian(Math.PI))); // Archimedes' constant
constants.Add(Parameter.CreateConstant("e", Math.E)); // Euler's number
constants.Add(Parameter.CreateConstant("i", Complex.ImaginaryOne)); // Imaginary unit
constants.Add(Parameter.CreateConstant("g", 9.80665)); // Gravity on Earth
constants.Add(Parameter.CreateConstant("c", 299792458)); // Speed of Light (c0)
constants.Add(Parameter.CreateConstant("h", 6.62607004E-34)); // Planck Constant
constants.Add(Parameter.CreateConstant("F", 96485.33289)); // Faraday Constant
constants.Add(Parameter.CreateConstant("ε", 8.854187817E-12)); // Electric Constant (ε0)
constants.Add(Parameter.CreateConstant("µ", 1.2566370614E-6)); // Magnetic constant (µ0)
constants.Add(Parameter.CreateConstant("G", 6.64078E-11)); // Gravitational constant
constants.Add(Parameter.CreateConstant("α", 2.5029078750958928222839)); // Feigenbaum constant
constants.Add(Parameter.CreateConstant("σ", 5.670367E-8)); // Stefan-Boltzmann constant
constants.Add(Parameter.CreateConstant("γ", 0.57721566490153286060651)); // Euler–Mascheroni constant
AddConstant(Parameter.CreateConstant("π", AngleValue.Radian(Math.PI))); // Archimedes' constant
AddConstant(Parameter.CreateConstant("pi", AngleValue.Radian(Math.PI))); // Archimedes' constant
AddConstant(Parameter.CreateConstant("e", Math.E)); // Euler's number
AddConstant(Parameter.CreateConstant("i", Complex.ImaginaryOne)); // Imaginary unit
AddConstant(Parameter.CreateConstant("g", 9.80665)); // Gravity on Earth
AddConstant(Parameter.CreateConstant("c", 299792458)); // Speed of Light (c0)
AddConstant(Parameter.CreateConstant("h", 6.62607004E-34)); // Planck Constant
AddConstant(Parameter.CreateConstant("F", 96485.33289)); // Faraday Constant
AddConstant(Parameter.CreateConstant("ε", 8.854187817E-12)); // Electric Constant (ε0)
AddConstant(Parameter.CreateConstant("µ", 1.2566370614E-6)); // Magnetic constant (µ0)
AddConstant(Parameter.CreateConstant("G", 6.64078E-11)); // Gravitational constant
AddConstant(Parameter.CreateConstant("α", 2.5029078750958928222839)); // Feigenbaum constant
AddConstant(Parameter.CreateConstant("σ", 5.670367E-8)); // Stefan-Boltzmann constant
AddConstant(Parameter.CreateConstant("γ", 0.57721566490153286060651)); // Euler–Mascheroni constant
}

/// <summary>
Expand All @@ -121,48 +132,13 @@ private void InitializeConstants()
/// </returns>
public IEnumerator<Parameter> GetEnumerator()
{
foreach (var item in constants)
foreach (var (_, item) in constants)
yield return item;

foreach (var item in collection)
foreach (var (_, item) in collection)
yield return item;
}

/// <summary>
/// Gets or sets the value of variable.
/// </summary>
/// <value>
/// The value of parameter.
/// </value>
/// <param name="index">The index of variable.</param>
/// <returns>The value of variable.</returns>
public object this[int index]
{
get
{
if (index < 0 || index >= constants.Count + collection.Count)
throw new IndexOutOfRangeException();

if (index < constants.Count)
return constants.ElementAt(index).Value;

return collection.ElementAt(index - constants.Count).Value;
}
set
{
if (index < 0 || index >= constants.Count + collection.Count)
throw new IndexOutOfRangeException();

if (index < constants.Count)
throw new ParameterIsReadOnlyException(Resource.ReadOnlyError, collection.ElementAt(index).Key);

var element = collection.ElementAt(index - constants.Count);
element.Value = value;

OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}

/// <summary>
/// Gets or sets the value of variable.
/// </summary>
Expand All @@ -179,8 +155,7 @@ public IEnumerator<Parameter> GetEnumerator()
}
set
{
var param = collection.FirstOrDefault(p => p.Key == key);
if (param == null)
if (!collection.TryGetValue(key, out var param))
{
Add(key, value);
}
Expand All @@ -192,14 +167,15 @@ public IEnumerator<Parameter> GetEnumerator()
}
}

private void AddConstant(Parameter parameter)
=> constants.Add(parameter.Key, parameter);

private Parameter GetParameterByKey(string key)
{
var item = collection.FirstOrDefault(p => p.Key == key);
if (!(item is null))
return item;
if (collection.TryGetValue(key, out var param))
return param;

var param = constants.FirstOrDefault(p => p.Key == key);
if (!(param is null))
if (constants.TryGetValue(key, out param))
return param;

throw new KeyNotFoundException(string.Format(CultureInfo.InvariantCulture, Resource.VariableNotFoundExceptionError, key));
Expand All @@ -218,18 +194,11 @@ public void Add(Parameter param)
if (param.Type == ParameterType.Constant)
throw new ArgumentException(Resource.ConstError);

collection.Add(param);
collection.Add(param.Key, param);

OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, param));
}

/// <summary>
/// Adds the specified element to a set.
/// </summary>
/// <param name="key">The name of variable.</param>
public void Add(string key)
=> Add(new Parameter(key, 0));

/// <summary>
/// Adds the specified element to a set.
/// </summary>
Expand All @@ -251,8 +220,7 @@ public void Remove(Parameter param)
if (param.Type == ParameterType.Constant)
throw new ArgumentException(Resource.ConstError);

collection.Remove(param);

collection.Remove(param.Key);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, param));
}

Expand Down Expand Up @@ -285,48 +253,19 @@ public void Clear()
/// <param name="param">The element.</param>
/// <returns><c>true</c> if the object contains the specified element; otherwise, <c>false</c>.</returns>
public bool Contains(Parameter param)
=> collection.Contains(param) || constants.Contains(param);

/// <summary>
/// Determines whether an object contains the specified element.
/// </summary>
/// <param name="param">The element.</param>
/// <returns><c>true</c> if the object contains the specified element; otherwise, <c>false</c>.</returns>
public bool ContainsInConstants(Parameter param)
=> constants.Contains(param);

/// <summary>
/// Determines whether an object contains the specified key.
/// </summary>
/// <param name="key">The name of variable.</param>
/// <returns><c>true</c> if the object contains the specified key; otherwise, <c>false</c>.</returns>
public bool ContainsKey(string key)
{
return collection.FirstOrDefault(p => p.Key == key) != null || constants.FirstOrDefault(p => p.Key == key) != null;
if (param == null)
throw new ArgumentNullException(nameof(param));

return ContainsKey(param.Key);
}

/// <summary>
/// Determines whether an object contains the specified key.
/// </summary>
/// <param name="key">The name of variable.</param>
/// <returns><c>true</c> if the object contains the specified key; otherwise, <c>false</c>.</returns>
public bool ContainsKeyInConstants(string key)
=> constants.FirstOrDefault(p => p.Key == key) != null;

/// <summary>
/// Gets the constants.
/// </summary>
/// <value>
/// The constants.
/// </value>
public IEnumerable<Parameter> Constants => constants;

/// <summary>
/// Gets the collection of variables.
/// </summary>
/// <value>
/// The collection.
/// </value>
public IEnumerable<Parameter> Collection => collection;
public bool ContainsKey(string key)
=> collection.ContainsKey(key) || constants.ContainsKey(key);
}
}
14 changes: 14 additions & 0 deletions xFunc.Maths/Expressions/ExpressionParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using xFunc.Maths.Expressions.Collections;

namespace xFunc.Maths.Expressions
Expand Down Expand Up @@ -48,6 +49,19 @@ public ExpressionParameters(FunctionCollection functions)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ExpressionParameters"/> class.
/// </summary>
/// <param name="parameters">Expression parameters.</param>
public ExpressionParameters(ExpressionParameters parameters)
{
if (parameters == null)
throw new ArgumentNullException(nameof(parameters));

Variables = new ParameterCollection(parameters.Variables);
Functions = parameters.Functions;
}

/// <summary>
/// Initializes a new instance of the <see cref="ExpressionParameters"/> class.
/// </summary>
Expand Down
9 changes: 4 additions & 5 deletions xFunc.Maths/Expressions/UserFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,14 @@ public object Execute(ExpressionParameters? parameters)
if (parameters == null)
throw new ArgumentNullException(nameof(parameters));

var func = parameters.Functions.GetKeyByKey(this);
var func = parameters.Functions.GetKey(this);

var newParameters = new ParameterCollection(parameters.Variables.Collection);
var newParams = new ExpressionParameters(parameters);
for (var i = 0; i < ParametersCount; i++)
if (func.arguments[i] is Variable arg)
newParameters[arg.Name] = (double)arguments[i].Execute(parameters);
newParams.Variables[arg.Name] = arguments[i].Execute(parameters);

var expParam = new ExpressionParameters(newParameters, parameters.Functions);
return parameters.Functions[this].Execute(expParam);
return parameters.Functions[this].Execute(newParams);
}

/// <summary>
Expand Down
3 changes: 1 addition & 2 deletions xFunc.Maths/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
using System.Collections.Generic;
using xFunc.Maths.Expressions;
using xFunc.Maths.Expressions.Collections;
using xFunc.Maths.Tokenization;

namespace xFunc.Maths
{
Expand Down Expand Up @@ -77,7 +76,7 @@ public static ParameterCollection GetParameters(IExpression expression)
/// <param name="expression">The expression.</param>
/// <returns>The collection of expression parts.</returns>
/// <exception cref="ArgumentNullException">The <paramref name="expression"/> variable is null.</exception>
public static IEnumerable<IExpression> ConvertExpressionToCollection(IExpression expression)
public static List<IExpression> ConvertExpressionToCollection(IExpression expression)
{
if (expression == null)
throw new ArgumentNullException(nameof(expression));
Expand Down

0 comments on commit 85369cf

Please sign in to comment.