Files
Skeleton/src/Algebra/ScalarFieldStructure/FieldStructure.cs
2024-06-21 21:48:07 +08:00

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/>
/// &lt;D&gt; &lt;/D&gt; &lt;C&gt; &lt;/C&gt; &lt;CSPLIT/&gt;<br/>
/// &lt;VECTOR&gt; &lt;VSPLIT/&gt; &lt;/VECTOR&gt;<br/>
/// &lt;MATRIX&gt; &lt;MSPLIT/&gt; &lt;/MSPLIT&gt;
/// </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;
}