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