/// <summary>No null checks.</summary> /// <param name="t">Source tensor (can be R1).</param> /// <param name="newSup">Copy's new superior.</param> /// <param name="inx">Copy's index inside new superior.</param> /// <param name="xCap">Extra capacity of all copied (sub)tensors (beyond existing Count).</param> /// <typeparam name="τ">Numeric type.</typeparam> /// <typeparam name="α">Arithmetic type.</typeparam> internal static Tnr <τ, α> CopyAsSubTnrβ <τ, α>(this Tnr <τ, α> t, Tnr <τ, α> newSup, int inx, int xCap = 0) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() { Assume.True(t.Dim == newSup.Strc[newSup.StrcInx + 1], () => "Source tensor's dimension does not equal the dimension of slot where copied subtensor will be placed."); if (t is Vec <τ, α> v) { return(v.CopyAsSubVecβ(newSup, inx, xCap)); } else { var nst = newSup.SubTnr <τ, α>(inx, t.Count + xCap); if (t.Rank == 2) { foreach (var(i, st) in t) { var sv = (Vec <τ, α>)st; sv.CopyAsSubVecβ <τ, α>(nst, i, xCap); } } else { foreach (var(i, st) in t) { st.CopyAsSubTnrβ(nst, i, xCap); } } return(nst); } }
public void SetT(Tnr <τ, α>?t, params int[] inxs) { Tnr <τ, α>?tnr = this; if (t != null) { int n = inxs.Length - 1; for (int i = 0; i < n; ++i) { if (!tnr.TryGetValue(inxs[i], out tnr)) // Crucial line: out tnr becomes the subtensor if found, if not it is created. { tnr = new Tnr <τ, α>(tnr !, 6); //new Tensor<τ,α>(Structure, tnr!.Rank - 1, tnr, 6); tnr.Superior !.AddSubTnr(inxs[i], tnr); } } var dict = (TnrBase <Tnr <τ, α> >)tnr; // tnr is now the proper subtensor. t.Superior = tnr; // Crucial: to make the added tensor truly a part of this tensor, we must set proper superior and structure. t.Strc = Strc; dict[inxs[n]] = t; } else { for (int i = 0; i < inxs.Length; ++i) { if (!tnr.TryGetValue(inxs[i], out tnr)) // t is null and the corresponding substructure does not exist. Leave as is. { return; } } tnr.Superior !.Remove(inxs[inxs.Length - 1]); } // Corresponding tensor exists. Remove. }
/// <summary>Tensor product of a vector with another tensor. Returns top tensor (null superior) as result.</summary> /// <param name="t2">Right hand operand.</param> /// <remarks> <see cref="TestRefs.TensorProduct"/> </remarks> public static Tnr <τ, α>?TnrProdTop <τ, α>(this Vec <τ, α>?v1, Tnr <τ, α>?t2) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() { if (v1 == null || t2 == null) { return(null); } return(v1.TnrProdTopß(t2)); }
/// <summary>No null checks.</summary> /// <param name="sup">Direct superior.</param> /// <param name="inx">Index inside superior.</param> /// <param name="cap">Initial capacity.</param> /// <typeparam name="τ">Numeric type.</typeparam> /// <typeparam name="α">Arithmetic type.</typeparam> internal static Vec <τ, α> SubVecβ <τ, α>(this Tnr <τ, α> sup, int inx, int cap = 6) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() { Assume.True(sup.Rank == 2, () => "Vector's superior rank not 2. You can only create a subvec with a rank 2 superior."); var vec = new Vec <τ, α>(sup, cap); sup[Vec <τ, α> .V, inx] = vec; return(vec); }
/// <summary>Vector getting/setting indexer. Use tnr[1f, 3] = null to remove an entry, should it exist.</summary> /// <param name="overloadDummy">Type float of first dummy argument specifies that we know we will be getting/setting a Vector.</param> /// <param name="inxs">A set of indices specifiying which Vector we want to set/get. The set length must reach exactly to Vector rank.</param> /// <remarks> <see cref="TestRefs.TensorVectorIndexer"/> </remarks> public Vec <τ, α>?this[Vec <τ, α> overloadDummy, params int[] inx] { get { Tnr <τ, α>?tnr = this; int n = inx.Length - 1; for (int i = 0; i < n; ++i) { if (!tnr.TryGetValue(inx[i], out tnr)) { return(null); } } if (tnr.TryGetValue(inx[n], out tnr)) // No problem with null. { return((Vec <τ, α>)tnr); // Same. } else { return(null); } } set { Tnr <τ, α>?tnr = this; if (value != null) { int n = inx.Length - 1; // Entry one before last chooses tensor, last chooses vector. for (int i = 0; i < n; ++i) { if (tnr.TryGetValue(inx[i], out Tnr <τ, α>?tnr2)) { tnr = tnr2; } else // Tensor does not exist in an intermediate rank. { tnr = new Tnr <τ, α>(tnr, 4); //new Tensor<τ,α>(Structure, tnr.Rank - 1, tnr, 4); tnr.Superior !.Add(inx[i], tnr); } } var dict = (TnrBase <Tnr <τ, α> >)tnr; // Tnr now refers to either a prexisting R2 tensor or a freshly created one. value.Superior = tnr; // Crucial: to make the added vector truly a part of this tensor, we must set proper superior and structure. value.Strc = Strc; dict[inx[n]] = value; } // We do not check that the value is a vector beforehand. It is assumed that the user used indexer correctly. else { int n = inx.Length; // Last entry chooses vector. for (int i = 0; i < n; ++i) { if (!tnr.TryGetValue(inx[i], out tnr)) { return; } } tnr.Superior !.Remove(inx[n - 1]); } } // Vector.Superior.Remove }
public static Tnr <τ, α>?ContractTopPart2 <τ, α>(this Vec <τ, α> v1, Tnr <τ, α> t2, int rankInx2, List <int> strc, int conDim) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() { if (t2.Rank > 2) // Result is tensor. { Tnr <τ, α>?elimTnr2, sumand; var sum = TopTnr <τ, α>(strc); // Set sum to a zero tensor. for (int i = 0; i < conDim; ++i) { elimTnr2 = t2.ReduceRankTop(rankInx2, i); if (v1.Scals.TryGetValue(i, out var s) && elimTnr2 != null) { sumand = elimTnr2.MulTopβ(s); sum.SumIntoβ(sumand); } } if (sum.Count != 0) { return(sum); } else { return(null); } } else if (t2.Rank == 2) { Tnr <τ, α>?elimTnr2; Vec <τ, α>?elimVec2, sumand; var sum = TopVec <τ, α>(strc[0]); for (int i = 0; i < conDim; ++i) { elimTnr2 = t2.ReduceRankTop(rankInx2, i); if (elimTnr2 != null) { elimVec2 = (Vec <τ, α>?)t2.ReduceRankTop(rankInx2, i); if (v1.Scals.TryGetValue(i, out var s) && elimVec2 != null) { sumand = elimVec2.MulTopß(s); sum.SumIntoß(sumand); } } } if (sum.Count != 0) { return(sum); } else { return(null); } } else // Result is scalar. { throw new ArgumentException("Explicitly cast t2 to vector before using contract."); } }
/// <summary>Copies substructure from specified tensor directly into Structure.</summary> /// <param name="tnr">Source.</param> protected void AssignStructFromSubStruct(Tnr <τ, α> tnr) // FIXME: Remove this after the copy specs fixes. { Strc.Clear(); var subStruct = tnr.Strc.Skip(tnr.StrcInx); foreach (var emt in subStruct) { Strc.Add(emt); } }
public Tnr <τ, α> GetNonNullTnr(params int[] inxs) { Tnr <τ, α>?tnr = this; for (int i = 0; i < inxs.Length; ++i) { if (!tnr.TryGetValue(inxs[i], out tnr)) { throw new NullReferenceException("Expected a non-null tensor at specified location."); } } return(tnr); }
public Tnr <τ, α>?GetT(params int[] inxs) { Tnr <τ, α>?tnr = this; for (int i = 0; i < inxs.Length; ++i) { if (!tnr.TryGetValue(inxs[i], out tnr)) { return(null); } } return(tnr); }
internal void SetSubTnr(int inx, Tnr <τ, α>?tnr) { if (tnr != null) { base[inx] = tnr; tnr.Superior = this; tnr.Strc = Strc; } else { Remove(inx); } }
/// <summary>No null checks.</summary> /// <param name="v">Copy source.</param> /// <param name="newSup">The copied vector's superior.</param> /// <param name="inx">New index inside superior.</param> /// <param name="xCap">Extra capacity of copied vector (beyond the number of elements).</param> /// <typeparam name="τ">Numeric type.</typeparam> /// <typeparam name="α">Arithmetic type.</typeparam> internal static Vec <τ, α> CopyAsSubVecβ <τ, α>(this Vec <τ, α> v, Tnr <τ, α> newSup, int inx, int xCap = 0) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() { Assume.True(v.Dim == newSup.Strc[newSup.StrcInx + 1], () => "Source vector's dimension does not equal the dimension of slot where copied subvector will be placed."); var copy = SubVec <τ, α>(newSup, inx, v.Count + xCap); // New superior's rank will be checked here. foreach (var(i, s) in v.Scals) { copy.Add(i, s); } return(copy); }
public static Vec <τ, α>?MulSub <τ, α>(this Vec <τ, α>?vec, τ scal, Tnr <τ, α> sup, int inx) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() { α alg = new α(); if (vec == null || alg.IsZero(scal)) { return(null); } else { return(vec.MulSubß(scal, sup, inx)); } }
/// <summary>No null checks.</summary> /// <param name="sup">Direct superior.</param> /// <param name="inx">Index inside superior.</param> /// <param name="cap">Capacity of internal dictionary.</param> /// <typeparam name="τ">Numeric type.</typeparam> /// <typeparam name="α">Arithmetic type.</typeparam> internal static Tnr <τ, α> SubTnrβ <τ, α>(this Tnr <τ, α> sup, int inx, int cap = 6) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() { Assume.True(sup.Rank > 1, () => "Superior's rank too low. Cannot create a subtensor on a vector."); if (sup.Rank > 2) { var tnr = new Tnr <τ, α>(sup, cap); sup[Tnr <τ, α> .T, inx] = tnr; return(tnr); } else { return(sup.SubVecβ(inx, cap)); } }
/// <summary>No null checks.</summary> /// <param name="t">Source tensor (can be R1).</param> /// <param name="xCap">Extra capacity of all copied (sub)tensors (beyond existing Count).</param> /// <typeparam name="τ">Numeric type.</typeparam> /// <typeparam name="α">Arithmetic type.</typeparam> internal static Tnr <τ, α> CopyAsTopTnrβ <τ, α>(this Tnr <τ, α> t, int xCap = 0) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() { if (t is Vec <τ, α> v) { return(v.CopyAsTopVecβ(xCap)); } else { var newStrc = t.Substrc; var copy = TopTnr <τ, α>(newStrc, t.Count + xCap); foreach (var(i, st) in t) { st.CopyAsSubTnrβ <τ, α>(copy, i, xCap); } return(copy); } }
/// <summary>Tensor getting/setting indexer.</summary> /// <param name="overloadDummy">Type uint of first dummy argument specifies that we know we will be getting/setting a Tensor.</param> /// <param name="inxs">A set of indices specifiying which Tensor we want to set/get. The set length must not reach all the way out to scalar rank.</param> public Tnr <τ, α>?this[Tnr <τ, α> overloadDummy, params int[] inxs] { get { Tnr <τ, α>?tnr = this; for (int i = 0; i < inxs.Length; ++i) { if (!tnr.TryGetValue(inxs[i], out tnr)) { return(null); } } return(tnr); } // No problem with tnr being null. We return above. set { Tnr <τ, α>?tnr = this; if (value != null) { int n = inxs.Length - 1; for (int i = 0; i < n; ++i) { if (!tnr.TryGetValue(inxs[i], out tnr)) // Crucial line: out tnr becomes the subtensor if found, if not it is created { tnr = new Tnr <τ, α>(tnr !, 6); //new Tensor<τ,α>(Structure, tnr!.Rank - 1, tnr, 6); tnr.Superior !.AddSubTnr(inxs[i], tnr); } } var dict = (TnrBase <Tnr <τ, α> >)tnr; // tnr is now the proper subtensor. value.Superior = tnr; // Crucial: to make the added tensor truly a part of this tensor, we must set proper superior and structure. value.Strc = Strc; dict[inxs[n]] = value; } else { for (int i = 0; i < inxs.Length; ++i) { if (!tnr.TryGetValue(inxs[i], out tnr)) { return; } } tnr.Superior !.Remove(inxs[inxs.Length - 1]); } } }
/// <summary>Creates a top tensor from an array span.</summary> /// <param name="span">Array span of values.</param> /// <param name="strc">Structure.</param> /// <typeparam name="τ">Numeric type.</typeparam> /// <typeparam name="α">Arithmetic type.</typeparam> public static Tnr <τ, α>?TopTnrFromSpan <τ, α>(Span <τ> span, params int[] strc) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() { int rank = strc.Length; if (rank == 1) { return(TopVecFromSpan <τ, α>(span)); } else { var res = new Tnr <τ, α>(strc.ToList(), strc[0]); // Empty tensor that enters recursion. Recursion(span, 0, res); return(res.Count != 0 ? res : null); } void Recursion(Span <τ> spn, int slot, Tnr <τ, α> tgt) // Span and natural slot index to which it belongs. { int nIter = strc[slot]; // As many iterations as slot dimension. int nEmtsInSpan = spn.Length / nIter; if (tgt.Rank > 2) { for (int i = 0; i < nIter; ++i) // Over each tensor. Create new spans and run recursion on them. { var newSpn = spn.Slice(i * nEmtsInSpan, nEmtsInSpan); var subTnr = new Tnr <τ, α>(tgt, strc[slot]); Recursion(newSpn, slot + 1, subTnr); if (subTnr.Count != 0) { tgt.Add(i, subTnr); } } } else // We are at rank 2, subrank = vector rank. { for (int i = 0; i < nIter; ++i) { var newSlc = spn.Slice(i * nEmtsInSpan, nEmtsInSpan); var subVec = SubVecFromSpan <τ, α>(newSlc, tgt, i); } } } }
public Vec <τ, α> GetNonNullVec(params int[] inx) { Tnr <τ, α>?tnr = this; int n = inx.Length - 1; for (int i = 0; i < n; ++i) { if (!tnr.TryGetValue(inx[i], out tnr)) { throw new NullReferenceException("Expected a non-null tensor at specified location."); } } if (tnr.TryGetValue(inx[n], out tnr)) { return((Vec <τ, α>)tnr); } else { throw new NullReferenceException("Expected a non-null vector at specified location."); }; }
public Vec <τ, α>?GetV(params int[] inx) { Tnr <τ, α>?tnr = this; int n = inx.Length - 1; for (int i = 0; i < n; ++i) { if (!tnr.TryGetValue(inx[i], out tnr)) { return(null); } } if (tnr.TryGetValue(inx[n], out tnr)) // No problem with null. { return((Vec <τ, α>)tnr); // Same. } else { return(null); } }
internal static Tnr <τ, α> TnrProdTopß <τ, α>(this Vec <τ, α> v1, Tnr <τ, α> t2) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() { if (t2.Rank > 1) { int newRank = v1.Rank + t2.Rank; var strc1 = v1.EnumSubstrc(); var strc2 = t2.EnumSubstrc(); var newStrc = strc1.Concat(strc2).ToList(); // We must substitute this vector with a tensor whose elements are multiples of tnr2. var prod = TopTnr <τ, α>(newStrc, v1.Scals.Count); foreach (var(i, s1) in v1.Scals) { t2.MulSubβ(s1, prod, i); } return(prod); } else { var v2 = (Vec <τ, α>)t2; return(v1.TnrProdTopß(v2)); } }
/// <summary>Creates a non-top vector from an array span. Adds it to its specified superior at the specified index.</summary> /// <param name="span">Array span of values.</param> /// <param name="sup">Direct superior with an existing structure.</param> /// <param name="inx">Index inside superior.</param> /// <typeparam name="τ">Numeric type.</typeparam> /// <typeparam name="α">Arithmetic type.</typeparam> public static Vec <τ, α>?SubVecFromSpan <τ, α>(Span <τ> span, Tnr <τ, α> sup, int inx) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() { Assume.True(sup.Rank == 2, () => "Vector's superior rank not 2. You can only create a subvector with a rank 2 superior."); α alg = new α(); var vec = new Vec <τ, α>(sup, span.Length); for (int i = 0; i < span.Length; ++i) { if (!alg.IsZero(span[i])) { vec.Add(i, span[i]); } } if (vec.Count > 0) // Created vector is not empty. { sup[Vec <τ, α> .V, inx] = vec; return(vec); } else { return(null); } }
/// <summary>Compares substructures and values.</summary> /// <param name="tnr2">Tensor to compare to.</param> public bool Equals(Tnr <τ, α>?tnr2) => this.Equalsβ <τ, α>(tnr2);
[MaybeNull] // Getter may return null. public virtual τ this[params int[] inx] { get { α alg = new α(); Tnr <τ, α>?tnr = this; int n = inx.Length - 2; for (int i = 0; i < n; ++i) { if (!tnr.TryGetValue(inx[i], out tnr)) { return(alg.Zero); } } if (tnr.TryGetValue(inx[n], out tnr)) // No probelm with null. { var vec = (Vec <τ, α>)tnr; // Same. if (vec.Scals.TryGetValue(inx[n + 1], out τ val)) { return(val); } } α alg2 = new α(); return(alg.Zero); } set { Tnr <τ, α>?tnr = this; Tnr <τ, α>?tnr2; // Temporary to avoid null problem below. Vec <τ, α> vec; α alg = new α(); if (!alg.IsZero(value)) { if (inx.Length > 1) // At least a 2nd rank tensor. { int n = inx.Length - 2; for (int i = 0; i < n; ++i) // This loop is entered only for a 3rd rank tensor or above. { if (tnr.TryGetValue(inx[i], out tnr2)) { tnr = tnr2; } else { tnr = new Tnr <τ, α>(tnr, 6); //new Tensor<τ,α>(Structure, tnr.Rank - 1, tnr, 6); tnr.Superior !.Add(inx[i], tnr); } } if (tnr.TryGetValue(inx[n], out tnr2)) // Does vector exist? { vec = (Vec <τ, α>)tnr2; } else { vec = new Vec <τ, α>(Strc, tnr, 4); tnr.Add(inx[n], vec); } vec.Scals[inx[n + 1]] = value; } } else { int n = inx.Length - 1; for (int i = 0; i < n; ++i) { if (!tnr.TryGetValue(inx[i], out tnr)) { return; } } vec = (Vec <τ, α>)tnr; vec.Scals.Remove(inx[n]); } } }
internal static Vec <τ, α> MulSubß <τ, α>(this Vec <τ, α> vec, [DisallowNull] τ scal, Tnr <τ, α> sup, int inx) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() { α alg = new α(); var newVec = TnrFactory.SubVec <τ, α>(sup, inx); foreach (var(i, s) in vec) { newVec.Add(i, alg.Mul(scal, s) !); // Return of Mul is not null zero (if both inputs were not zero): } return(newVec); }
/// <summary>Creates a deep copy of a tensor as a non-top tensor (non-null superior).</summary> /// <param name="t">Copy source.</param> /// <param name="newSup">The copied tensor's superior.</param> /// <param name="inx">New index inside superior.</param> /// <param name="xCap">Extra capacity of all copied (sub)tensors (beyond existing Count).</param> /// <typeparam name="τ">Numeric type.</typeparam> /// <typeparam name="α">Arithmetic type.</typeparam> public static Tnr <τ, α>?CopyAsSubTnr <τ, α>(this Tnr <τ, α>?t, Tnr <τ, α> newSup, int inx, int xCap = 0) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() => t != null?t.CopyAsSubTnrβ(newSup, inx, xCap) : null;
/// <summary>Creates a non-top vector (non-null superior) with specified initial capacity. Adds it to its specified superior at the specified index. Dimension is inferred from superior's structure.</summary> /// <param name="sup">Direct superior.</param> /// <param name="inx">Index inside superior.</param> /// <param name="cap">Initial capacity.</param> /// <typeparam name="τ">Numeric type.</typeparam> /// <typeparam name="α">Arithmetic type.</typeparam> public static Vec <τ, α> SubVec <τ, α>(this Tnr <τ, α>?sup, int inx, int cap = 6) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() => sup != null?SubVecβ(sup, inx, cap) : throw new ArgumentNullException(nameof(sup), "Specified superior was null.");
public static Tnr <τ, α>?ContractTop <τ, α>(this Vec <τ, α> v1, Tnr <τ, α> t2, int slot2) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() { (List <int> strc, _, int rankInx2, int conDim) = v1.ContractTopPart1(t2, 1, slot2); return(ContractTopPart2(v1, t2, rankInx2, strc, conDim)); }
/// <summary>Creates a deep copy of a tensor as a top tensor (null superior).</summary> /// <param name="t">Source tensor (can be R1).</param> /// <param name="xCap">Extra capacity of all copied (sub)tensors (beyond existing Count).</param> /// <typeparam name="τ">Numeric type.</typeparam> /// <typeparam name="α">Arithmetic type.</typeparam> public static Tnr <τ, α>?CopyAsTopTnr <τ, α>(this Tnr <τ, α>?t, int xCap = 0) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() => t != null?t.CopyAsTopTnrβ(xCap) : null;
/// <summary>Constructor with redundancy, used internally.</summary> /// <param name="strc">Structure (absorbed).</param> /// <param name="sup">Direct superior.</param> /// <param name="cap">Capacity of internal dictionary.</param> internal Vec(List <int> strc, Tnr <τ, α>?sup, int cap) : base(strc, 1, sup, 0) // Zero capacity for dictionary holding tensors. { Scals = new Dictionary <int, τ>(cap); }
/// <summary>Creates a deep copy of a vector as a non-top vector (non-null superior).</summary> /// <param name="v">Copy source.</param> /// <param name="newSup">The copied vector's superior.</param> /// <param name="inx">New index inside superior.</param> /// <param name="xCap">Extra capacity of copied vector (beyond the number of elements).</param> /// <typeparam name="τ">Numeric type.</typeparam> /// <typeparam name="α">Arithmetic type.</typeparam> public static Vec <τ, α>?CopyAsSubVec <τ, α>(this Vec <τ, α>?v, Tnr <τ, α> newSup, int inx, int xCap = 0) where τ : notnull, IEquatable <τ>, IComparable <τ> where α : IAlgebra <τ>, new() => v != null?v.CopyAsSubVecβ(newSup, inx, xCap) : null;
/// <summary>Creates a non-top vector with specified superior and initial capacity. Does not add the new vector to its superior or check whether the superior is rank 2.</summary> /// <param name="sup">Direct superior.</param> /// <param name="cap">Capacity of internal dictionary.</param> internal Vec(Tnr <τ, α> sup, int cap) : this(sup.Strc, sup, cap) { }