M2
This commit is contained in:
325
src/Algebra/ScalarFieldStructure/FieldStructure.cs
Normal file
325
src/Algebra/ScalarFieldStructure/FieldStructure.cs
Normal file
@@ -0,0 +1,325 @@
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user