326 lines
11 KiB
C#
326 lines
11 KiB
C#
using System.Numerics;
|
|
using Skeleton.Algebra.Extensions;
|
|
using Skeleton.DataStructure.Packs;
|
|
|
|
namespace Skeleton.Algebra.ScalarFieldStructure;
|
|
|
|
/// <summary>
|
|
/// operations / structure of the field
|
|
/// </summary>
|
|
public abstract class FieldStructure
|
|
{
|
|
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public abstract class FieldStructure<TScalar> : FieldStructure
|
|
{
|
|
|
|
/// <summary>
|
|
/// return the singleton base on type
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static FieldStructure<TScalar> Dispatch()
|
|
{
|
|
if (typeof(TScalar) == typeof(double))
|
|
return (RealFieldStructure.Structure as FieldStructure<TScalar>)!;
|
|
if (typeof(TScalar) == typeof(Complex))
|
|
return (ComplexFieldStructure.Structure as FieldStructure<TScalar>)!;
|
|
return ScalarFieldStructureProvider.GetOperation<TScalar>();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public FieldStructure()
|
|
{
|
|
StaticAccess<TScalar>.AdditionUnit = AdditionUnit;
|
|
StaticAccess<TScalar>.MultiplicationUnit = MultiplicationUnit;
|
|
StaticAccess<TScalar>.Structure = this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// addition in field
|
|
/// </summary>
|
|
/// <param name="self"></param>
|
|
/// <param name="other"></param>
|
|
/// <returns></returns>
|
|
public abstract TScalar Addition(TScalar self, TScalar other);
|
|
/// <summary>
|
|
/// addition unit of the field<br/>
|
|
/// a + unit = a for any a in field
|
|
/// </summary>
|
|
public abstract TScalar AdditionUnit { get; }
|
|
/// <summary>
|
|
/// multiplication in field
|
|
/// </summary>
|
|
/// <param name="self"></param>
|
|
/// <param name="other"></param>
|
|
/// <returns></returns>
|
|
public abstract TScalar Multiplication(TScalar self, TScalar other);
|
|
/// <summary>
|
|
/// multiplication unit of the field<br/>
|
|
/// unit * a = a for any a in the field except the addition unit
|
|
/// </summary>
|
|
public abstract TScalar MultiplicationUnit { get; }
|
|
/// <summary>
|
|
/// inverse of element under addition<br/>
|
|
/// a + AddInv(a) = unit(addition) for any a in field
|
|
/// </summary>
|
|
/// <param name="self"></param>
|
|
/// <returns></returns>
|
|
public abstract TScalar AdditionInverse(TScalar self);
|
|
/// <summary>
|
|
/// inverse of element under multiplication<br/>
|
|
/// a * MulInv(a) = unit(multiplication) for any a in field except the addition unit
|
|
/// </summary>
|
|
/// <param name="self"></param>
|
|
/// <returns></returns>
|
|
public abstract TScalar MultiplicationInverse(TScalar self);
|
|
/// <summary>
|
|
/// a + AddInv(b)
|
|
/// </summary>
|
|
/// <param name="self"></param>
|
|
/// <param name="other"></param>
|
|
/// <returns></returns>
|
|
public virtual TScalar Subtraction(TScalar self, TScalar other)
|
|
=> Addition(self, AdditionInverse(other));
|
|
|
|
/// <summary>
|
|
/// a * MulInv(b)
|
|
/// </summary>
|
|
/// <param name="self"></param>
|
|
/// <param name="other"></param>
|
|
/// <returns></returns>
|
|
public virtual TScalar Division(TScalar self, TScalar other)
|
|
=> Multiplication(self, MultiplicationInverse(other));
|
|
/// <summary>
|
|
/// conjugate of the scalar
|
|
/// </summary>
|
|
/// <param name="self"></param>
|
|
/// <returns></returns>
|
|
public abstract TScalar Conj(TScalar self);
|
|
/// <summary>
|
|
/// if two elements are close to each other in the field
|
|
/// </summary>
|
|
/// <param name="self"></param>
|
|
/// <param name="other"></param>
|
|
/// <param name="absTol"></param>
|
|
/// <param name="relTol"></param>
|
|
/// <returns></returns>
|
|
public abstract bool IsEqualApprox(TScalar self, TScalar other, double? absTol=null, double? relTol = null);
|
|
|
|
/// <summary>
|
|
/// tolerance to check if two scalars are close
|
|
/// </summary>
|
|
public double AbsoluteTolerance { get; set; } = 1E-8d;
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public double RelativeTolerance { get; set; } = 1E-5d;
|
|
|
|
/// <summary>
|
|
/// if calculation in field won't introduce error, override this and leave it empty
|
|
/// otherwise, provide method to reduce the error here
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <returns></returns>
|
|
public virtual TScalar Fix(TScalar x)
|
|
{
|
|
if (IsEqualApprox(x, AdditionUnit))
|
|
return AdditionUnit;
|
|
if (IsEqualApprox(x, MultiplicationUnit))
|
|
return MultiplicationUnit;
|
|
return x;
|
|
}
|
|
|
|
/// <summary>
|
|
/// homomorphism from scalar field to real<br/>
|
|
/// ignore if not applicable
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <returns></returns>
|
|
public virtual double AsReal(TScalar x) => IsEqualApprox(x, AdditionUnit) ? 0 : 1;
|
|
/// <summary>
|
|
/// conjugated square xx* when field is real/complex
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <returns></returns>
|
|
public double ConjX2(TScalar x) => AsReal(Multiplication(x, Conj(x)));
|
|
|
|
/// <summary>
|
|
/// homomorphism from real to scalar<br/>
|
|
/// ignore if not applicable
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <returns></returns>
|
|
public virtual TScalar FromReal(double x) => x.IsEqualApprox(0) ? AdditionUnit : MultiplicationUnit;
|
|
/// <summary>
|
|
/// readable string representation of data
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <returns></returns>
|
|
public string Representation(TScalar x) => RawRepresentation(Fix(x));
|
|
|
|
/// <summary>
|
|
/// representation of the original data, without fix
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <returns></returns>
|
|
public virtual string RawRepresentation(TScalar x) => $"{x}";
|
|
|
|
/// <summary>
|
|
/// code to construct object in python
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <returns></returns>
|
|
public string PythonRepresentation(TScalar x) => RawPythonRepresentation(Fix(x));
|
|
|
|
/// <summary>
|
|
/// code to construct scalar object in python<br/>
|
|
/// ignore if not applicable
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <returns></returns>
|
|
public virtual string RawPythonRepresentation(TScalar x) => "";
|
|
/// <summary>
|
|
/// code to construct the object in c#
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <returns></returns>
|
|
public string CSharpRepresentation(TScalar x) => RawCSharpRepresentation(Fix(x));
|
|
/// <summary>
|
|
/// C# string for the original data
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <returns></returns>
|
|
public abstract string RawCSharpRepresentation(TScalar x);
|
|
|
|
/// <summary>
|
|
/// dump the object as string which can be restored exactly<br/>
|
|
/// ignore if not applicable<br/>
|
|
/// if override can not contain following string as substring<br/>
|
|
/// <D> </D> <C> </C> <CSPLIT/><br/>
|
|
/// <VECTOR> <VSPLIT/> </VECTOR><br/>
|
|
/// <MATRIX> <MSPLIT/> </MSPLIT>
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <returns></returns>
|
|
public virtual string DumpString(TScalar x) => "";
|
|
|
|
/// <summary>
|
|
/// method to restore a value from dump string<br/>
|
|
/// ignore if not applicable
|
|
/// </summary>
|
|
/// <param name="dumpString"></param>
|
|
/// <returns></returns>
|
|
public virtual TScalar Resolve(string dumpString) => AdditionUnit;
|
|
/// <summary>
|
|
/// max diff from zero
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <returns></returns>
|
|
public abstract double MaxError(TScalar a);
|
|
|
|
/// <summary>
|
|
/// homomorphism from field to complex<br/>
|
|
/// ignore if not applicable
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <returns></returns>
|
|
public virtual Complex ComplexCast(TScalar a) => IsEqualApprox(a, AdditionUnit) ? 0 : 1;
|
|
|
|
|
|
/// <summary>
|
|
/// K x R -> K<br/>
|
|
/// ignore if not applicable
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <param name="b"></param>
|
|
/// <returns></returns>
|
|
public virtual TScalar RealMul(TScalar a, double b) => a;
|
|
|
|
/// <summary>
|
|
/// for y in field, find x such that x*x = y
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <returns></returns>
|
|
public abstract TScalar SquareRoot(TScalar a);
|
|
|
|
/// <summary>
|
|
/// Absolute value
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <returns></returns>
|
|
public TScalar Abs(TScalar a) => SquareRoot(Multiplication(a, Conj(a)));
|
|
/// <summary>
|
|
/// a x^2 + b x + c = unit(add)
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <param name="b"></param>
|
|
/// <param name="c"></param>
|
|
/// <returns></returns>
|
|
public QuadraticRoots<TScalar> QuadraticRoot(TScalar a, TScalar b, TScalar c)
|
|
{
|
|
TScalar invB = AdditionInverse(b);
|
|
TScalar b2 = Multiplication(b, b);
|
|
TScalar ax2 = Addition(a, a);
|
|
TScalar ac = Multiplication(a, c);
|
|
TScalar acx2 = Addition(ac, ac);
|
|
TScalar acx4 = Addition(acx2, acx2);
|
|
TScalar x1 = Division(Addition(invB, SquareRoot(Subtraction(b2, acx4))), ax2);
|
|
TScalar x2 = Division(Subtraction(invB, SquareRoot(Subtraction(b2, acx4))), ax2);
|
|
return new QuadraticRoots<TScalar>(x1, x2);
|
|
}
|
|
|
|
internal TScalar WilkinsonShift(TScalar a1, TScalar b1, TScalar b2, TScalar a2)
|
|
{
|
|
QuadraticRoots<TScalar> es = QuadraticRoot(
|
|
AdditionUnit,
|
|
AdditionInverse(Addition(a1, a2)),
|
|
Subtraction(Multiplication(a1, a2), Multiplication(b1, b2))
|
|
);
|
|
TScalar k = a2;
|
|
TScalar s = Addition(Addition(Abs(a1), Abs(b1)), Addition(Abs(b2), Abs(a2)));
|
|
if (IsEqualApprox(s, AdditionUnit))
|
|
return k;
|
|
TScalar q = Multiplication(Division(b1, s), Division(b2, s));
|
|
|
|
if (IsEqualApprox(q, AdditionUnit))
|
|
return k;
|
|
TScalar p = Division(
|
|
Subtraction(Division(a1, s), Division(a2, s)),
|
|
Addition(MultiplicationUnit, MultiplicationUnit)
|
|
);
|
|
TScalar r = SquareRoot(Addition(Multiplication(p, p), q));
|
|
Complex cp = ComplexCast(p);
|
|
Complex cr = ComplexCast(r);
|
|
if (cp.Real * cr.Real + cp.Imaginary * cr.Imaginary < 0)
|
|
r = AdditionInverse(r);
|
|
k = Subtraction(k, Multiplication(s, Division(q, Addition(p, r))));
|
|
return k;
|
|
}
|
|
|
|
/// <summary>
|
|
/// homomorphism from complex to this field
|
|
/// </summary>
|
|
/// <param name="a"></param>
|
|
/// <returns></returns>
|
|
public virtual TScalar FromComplex(Complex a) => AdditionUnit;
|
|
|
|
|
|
/// <summary>
|
|
/// log of the element in the field
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <returns></returns>
|
|
public virtual TScalar Log(TScalar x) => AdditionUnit;
|
|
|
|
/// <summary>
|
|
/// exp of the element in the field
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <returns></returns>
|
|
public virtual TScalar Exp(TScalar x) => MultiplicationUnit;
|
|
}
|
|
|