Skip to content

Commit

Permalink
Merge pull request #67 from SpiceSharp/development
Browse files Browse the repository at this point in the history
v3.1.1
  • Loading branch information
svenboulanger authored Jun 26, 2021
2 parents d622fb4 + b2498bb commit b88f306
Show file tree
Hide file tree
Showing 61 changed files with 2,860 additions and 727 deletions.
34 changes: 32 additions & 2 deletions SpiceSharpBehavioral/Builders/Direct/ComplexBuilderHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static class ComplexBuilderHelper
/// <summary>
/// A set of default functions.
/// </summary>
public static readonly Dictionary<string, Func<Complex[], Complex>> Defaults = new Dictionary<string, Func<Complex[], Complex>>(StringComparer.OrdinalIgnoreCase)
public static Dictionary<string, Func<Complex[], Complex>> Defaults { get; set; } = new Dictionary<string, Func<Complex[], Complex>>(StringComparer.OrdinalIgnoreCase)
{
{ "abs", Abs },
{ "sgn", Sgn },
Expand Down Expand Up @@ -50,9 +50,15 @@ public static class ComplexBuilderHelper
{ "min", Min },
{ "max", Max },
{ "atan2", Atan2 },
{ "atanh", Atanh },
{ "hypot", Hypot },
{ "rnd", Random }, { "rand", Random },
{ "if", If }
{ "if", If },
{ "limit", Limit },
{ "db", Decibels },
{ "arg", args => args.Check(1)[0].Phase * 180.0 / Math.PI },
{ "real", args => args.Check(1)[0].Real },
{ "imag", args => args.Check(1)[0].Imaginary },
};

private static Complex[] Check(this Complex[] args, int expected)
Expand Down Expand Up @@ -84,6 +90,20 @@ private static void OnFunctionFound(object sender, FunctionFoundEventArgs<Comple
}
}

/// <summary>
/// Helper methods that changes the equality comparer for function names.
/// </summary>
/// <param name="comparer">The name comparer.</param>
public static void RemapFunctions(IEqualityComparer<string> comparer)
{
var nmap = new Dictionary<string, Func<Complex[], Complex>>(comparer);
foreach (var map in Defaults)
{
nmap.Add(map.Key, map.Value);
}
Defaults = nmap;
}

// No-argument functions
private static Complex Random(Complex[] args) { args.Check(0); return _rnd.NextDouble(); }

Expand Down Expand Up @@ -122,6 +142,11 @@ private static Complex Nint(Complex[] args)
var arg = args.Check(1)[0];
return new Complex(Math.Round(arg.Real, 0), Math.Round(arg.Imaginary, 0));
}
private static Complex Decibels(Complex[] args)
{
var arg = args.Check(1)[0];
return 10 * Math.Log10(arg.Real * arg.Real + arg.Imaginary * arg.Imaginary);
}

// Two-argument functions
private static Complex Pow(Complex[] args) { args.Check(2); return Complex.Pow(args[0], args[1]); }
Expand All @@ -136,10 +161,15 @@ private static Complex Round(Complex[] args)
return new Complex(Math.Round(arg.Real, n), Math.Round(arg.Imaginary, n));
}
private static Complex Atan2(Complex[] args) { args.Check(2); return Math.Atan2(args[0].Real, args[1].Real); }

private static Complex Atanh(Complex[] args) { args.Check(1); return HelperFunctions.Atanh(args[0]); }

private static Complex Hypot(Complex[] args) { args.Check(2); return HelperFunctions.Hypot(args[0], args[1]); }

// Three-argument functions
private static Complex If(Complex[] args) { args.Check(3); return args[0].Real > 0.5 ? args[1] : args[2]; }

private static Complex Limit(Complex[] args) { args.Check(3); return HelperFunctions.Limit(args[0], args[1], args[2]); }

// N-argument functions
private static Complex Pwl(Complex[] args)
Expand Down
26 changes: 24 additions & 2 deletions SpiceSharpBehavioral/Builders/Direct/RealBuilderHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static class RealBuilderHelper
/// <summary>
/// A set of default functions.
/// </summary>
public static readonly Dictionary<string, Func<double[], double>> Defaults = new Dictionary<string, Func<double[], double>>()
public static Dictionary<string, Func<double[], double>> Defaults { get; set; } = new Dictionary<string, Func<double[], double>>()
{
{ "abs", Abs },
{ "sgn", Sgn },
Expand Down Expand Up @@ -50,9 +50,15 @@ public static class RealBuilderHelper
{ "min", Min },
{ "max", Max },
{ "atan2", Atan2 },
{ "atanh", Atanh },
{ "hypot", Hypot },
{ "rnd", Random }, { "rand", Random },
{ "if", If }
{ "if", If },
{ "limit", Limit },
{ "real", args => args.Check(1)[0] },
{ "imag", args => 0.0 },
{ "arg", args => 0.0 },
{ "db", args => 20 * Log10(args) }
};

private static double[] Check(this double[] args, int expected)
Expand Down Expand Up @@ -84,6 +90,20 @@ private static void OnFunctionFound(object sender, FunctionFoundEventArgs<double
}
}

/// <summary>
/// Helper methods that changes the equality comparer for function names.
/// </summary>
/// <param name="comparer">The name comparer.</param>
public static void RemapFunctions(IEqualityComparer<string> comparer)
{
var nmap = new Dictionary<string, Func<double[], double>>(comparer);
foreach (var map in Defaults)
{
nmap.Add(map.Key, map.Value);
}
Defaults = nmap;
}

// No-argument functions
private static double Random(double[] args) { args.Check(0); return _rnd.NextDouble(); }

Expand Down Expand Up @@ -119,10 +139,12 @@ private static void OnFunctionFound(object sender, FunctionFoundEventArgs<double
private static double Max(double[] args) { args.Check(2); return Math.Max(args[0], args[1]); }
private static double Round(double[] args) { args.Check(2); return Math.Round(args[0], (int)args[1]); }
private static double Atan2(double[] args) { args.Check(2); return Math.Atan2(args[0], args[1]); }
private static double Atanh(double[] args) { args.Check(1); return HelperFunctions.Atanh(args[0]); }
private static double Hypot(double[] args) { args.Check(2); return HelperFunctions.Hypot(args[0], args[1]); }

// Three-argument functions
private static double If(double[] args) { args.Check(3); return args[0] > 0.5 ? args[1] : args[2]; }
private static double Limit(double[] args) { args.Check(3); return HelperFunctions.Limit(args[0], args[1], args[2]); }

// N-argument functions
private static double Pwl(double[] args)
Expand Down
65 changes: 65 additions & 0 deletions SpiceSharpBehavioral/Builders/Functions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,20 @@ public static bool Equals(Complex left, Complex right, double relTol, double abs
return true;
}

/// <summary>
/// Gets the real part of a complex number.
/// </summary>
/// <param name="arg">The argument.</param>
/// <returns>The real part.</returns>
public static Complex Real(Complex arg) => arg.Real;

/// <summary>
/// Gets the imaginary part of a complex number.
/// </summary>
/// <param name="arg">The argument.</param>
/// <returns>The imaginary part.</returns>
public static Complex Imag(Complex arg) => arg.Imaginary;

/// <summary>
/// Takes the natural logarithm.
/// </summary>
Expand Down Expand Up @@ -142,6 +156,34 @@ public static Complex Log10(Complex arg)
return Complex.Log10(arg);
}

/// <summary>
/// Gets the magnitude of the complex value in decibels.
/// </summary>
/// <param name="arg">The argument.</param>
/// <returns>The magnitude in decibels.</returns>
public static Complex Decibels(Complex arg) => 10 * Log10(arg.Real * arg.Real + arg.Imaginary * arg.Imaginary);

/// <summary>
/// Gets the phase of the complex value in degrees.
/// </summary>
/// <param name="arg">The argument.</param>
/// <returns>The phase in degrees.</returns>
public static Complex Phase(Complex arg) => arg.Phase * 180.0 / Math.PI;

/// <summary>
/// Computes the inverse arc tangent hyperbolic.
/// </summary>
/// <param name="arg">The argument.</param>
/// <returns>The result.</returns>
public static double Atanh(double arg) => 0.5 * Log(SafeDivide(1 + arg, 1 - arg));

/// <summary>
/// Computes the inverse arc tangent hyperbolic.
/// </summary>
/// <param name="arg">The argument.</param>
/// <returns>The result.</returns>
public static Complex Atanh(Complex arg) => 0.5 * Log(SafeDivide(1 + arg, 1 - arg));

/// <summary>
/// Raises a number to a power.
/// </summary>
Expand Down Expand Up @@ -436,6 +478,29 @@ public static double Sign(double arg)
/// <returns>The hypothenuse.</returns>
public static double Hypot(double y, double x) => Math.Sqrt(x * x + y * y);

/// <summary>
/// Returns the intermediate value of x, y, z.
/// </summary>
/// <param name="x">The argument</param>
/// <param name="y">Mininum value.</param>
/// <param name="z">Max value.</param>
/// <returns></returns>
public static double Limit(double x, double y, double z)
{
return Math.Min(Math.Max(x, Math.Min(y, z)), Math.Max(y, z));
}

/// <summary>
/// Returns the intermediate value of x, y, z.
/// </summary>
/// <param name="x">The argument</param>
/// <param name="y">Mininum value.</param>
/// <param name="z">Max value.</param>
/// <returns></returns>
public static Complex Limit(Complex x, Complex y, Complex z)
{
return Math.Min(Math.Max(x.Real, Math.Min(y.Real, z.Real)), Math.Max(y.Real, z.Real));
}
/// <summary>
/// Returns the hypothenuse (sqrt(|x|^2+|y|^2)).
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ private static readonly MethodInfo
/// <summary>
/// A set of default functions.
/// </summary>
public static readonly Dictionary<string, ApplyFunction> Defaults = new Dictionary<string, ApplyFunction>(StringComparer.OrdinalIgnoreCase)
public static Dictionary<string, ApplyFunction> Defaults { get; set; } = new Dictionary<string, ApplyFunction>(StringComparer.OrdinalIgnoreCase)
{
{ "abs", Abs },
{ "sgn", Sgn },
Expand All @@ -54,6 +54,7 @@ private static readonly MethodInfo
{ "acos", Acos }, { "arccos", Acos },
{ "atan", Atan }, { "arctan", Atan },
{ "atan2", Atan2 },
{ "atanh", Atanh },
{ "hypot", Hypot },
{ "u", U }, { "du(0)", Zero },
{ "u2", U2 }, { "du2(0)", DU2 },
Expand All @@ -69,7 +70,12 @@ private static readonly MethodInfo
{ "min", Min },
{ "max", Max },
{ "rnd", Random }, { "rand", Random },
{ "if", If }
{ "if", If },
{ "limit", Limit },
{ "db", Decibels },
{ "arg", Argument },
{ "real", (ils, args) => ils.Call(HelperFunctions.Real, args) },
{ "imag", (ils, args) => ils.Call(HelperFunctions.Imag, args) },
};

private static IReadOnlyList<Node> Check(this IReadOnlyList<Node> nodes, int expected)
Expand Down Expand Up @@ -98,6 +104,20 @@ private static void OnFunctionFound(object sender, FunctionFoundEventArgs<Comple
}
}

/// <summary>
/// Helper methods that changes the equality comparer for function names.
/// </summary>
/// <param name="comparer">The name comparer.</param>
public static void RemapFunctions(IEqualityComparer<string> comparer)
{
var nmap = new Dictionary<string, ApplyFunction>(comparer);
foreach (var map in Defaults)
{
nmap.Add(map.Key, map.Value);
}
Defaults = nmap;
}

// No-argument functions
private static void Random(IILState<Complex> ils, IReadOnlyList<Node> arguments)
{
Expand Down Expand Up @@ -138,6 +158,8 @@ private static void Nint(IILState<Complex> ils, IReadOnlyList<Node> arguments)
ils.PushInt(0);
ils.Generator.Emit(OpCodes.Call, _round);
}
private static void Decibels(IILState<Complex> ils, IReadOnlyList<Node> arguments) => ils.Call(HelperFunctions.Decibels, arguments);
private static void Argument(IILState<Complex> ils, IReadOnlyList<Node> arguments) => ils.Call(HelperFunctions.Phase, arguments);

// Two-argument functions
private static void Pow(IILState<Complex> ils, IReadOnlyList<Node> arguments) => ils.Call(Complex.Pow, arguments);
Expand All @@ -153,6 +175,7 @@ private static void Round(IILState<Complex> ils, IReadOnlyList<Node> arguments)
ils.Generator.Emit(OpCodes.Call, _round);
}
private static void Atan2(IILState<Complex> ils, IReadOnlyList<Node> arguments) => ils.Call(HelperFunctions.Atan2, arguments);
private static void Atanh(IILState<Complex> ils, IReadOnlyList<Node> arguments) => ils.Call(HelperFunctions.Atanh, arguments);
private static void Hypot(IILState<Complex> ils, IReadOnlyList<Node> arguments) => ils.Call(HelperFunctions.Hypot, arguments);

// Three-argument functions
Expand All @@ -164,6 +187,7 @@ private static void If(IILState<Complex> ils, IReadOnlyList<Node> arguments)
ilsc.PushDouble(0.5);
ilsc.PushCheck(OpCodes.Bgt_S, arguments[1], arguments[2]);
}
private static void Limit(IILState<Complex> ils, IReadOnlyList<Node> arguments) => ils.Call(HelperFunctions.Limit, arguments);

// N-argument functions
private static void Pwl(IILState<Complex> ils, IReadOnlyList<Node> arguments)
Expand Down
7 changes: 7 additions & 0 deletions SpiceSharpBehavioral/Builders/Functions/IILState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,12 @@ public interface IILState<T>
/// <param name="function">The function.</param>
/// <param name="args">The arguments.</param>
void Call(Func<T, T, T> function, IReadOnlyList<Node> args);

/// <summary>
/// Shorthand for calling a function with three arguments.
/// </summary>
/// <param name="function">The function.</param>
/// <param name="args">The arguments.</param>
void Call(Func<T, T, T, T> function, IReadOnlyList<Node> args);
}
}
17 changes: 16 additions & 1 deletion SpiceSharpBehavioral/Builders/Functions/ILState.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using SpiceSharp;
using SpiceSharp.Simulations;
using SpiceSharpBehavioral.Diagnostics;
using SpiceSharpBehavioral.Parsers.Nodes;
using System;
Expand Down Expand Up @@ -227,5 +226,21 @@ public void Call(Func<T, T, T> function, IReadOnlyList<Node> args)
else
Call(function, _invoke2, args);
}

/// <summary>
/// Calls the specified function.
/// </summary>
/// <param name="function">The function.</param>
/// <param name="args">The arguments.</param>
/// <exception cref="ArgumentMismatchException">Thrown if there aren't two arguments.</exception>
public void Call(Func<T, T, T, T> function, IReadOnlyList<Node> args)
{
if (args == null || args.Count != 3)
throw new ArgumentMismatchException(3, args?.Count ?? 0);
if (function.Target == null)
Call(null, function.GetMethodInfo(), args);
else
Call(function, _invoke2, args);
}
}
}
Loading

0 comments on commit b88f306

Please sign in to comment.