/// <summary> /// Helper function which takes the blades listed in 'B' and returns them sorted by grade /// in a double array. The relative order of blades of each grade left constant. /// </summary> /// <param name="B"></param> /// <param name="spaceDim">dimension of space of the algebra; used to determine the length of the returned double array.</param> /// <returns>'B' in an array of arrays, sorted by grade.</returns> private RefGA.BasisBlade[][] SortByGrade(RefGA.BasisBlade[] B, int spaceDim) { RefGA.BasisBlade[][] L = new RefGA.BasisBlade[spaceDim + 1][]; { // count, allocate number of elements of each grade // count number of blades for each grade int[] count = new int[spaceDim + 1]; for (int i = 0; i < B.Length; i++) { if (B[i].Grade() >= count.Length) { throw new Exception("G25.OM.SortByGrade(): unexpectedly high grade of basis blade: " + B[i].Grade()); } else { count[B[i].Grade()]++; } } // allocate for (int g = 0; g <= spaceDim; g++) { L[g] = new RefGA.BasisBlade[count[g]]; } } // sort all blades: int[] idx = new int[spaceDim + 1]; for (int i = 0; i < B.Length; i++) { L[B[i].Grade()][idx[B[i].Grade()]] = B[i]; idx[B[i].Grade()]++; } return(L); }
/// <summary> /// Little helper function for constructor. /// </summary> /// <returns>'basisBlades', but inside a newly allocated array of length 1.</returns> protected static RefGA.BasisBlade[][] ToDoubleArray(G25.rsbbp.BasisBlade[] basisBlades) { RefGA.BasisBlade[][] B = new RefGA.BasisBlade[1][]; B[0] = new RefGA.BasisBlade[basisBlades.Length]; for (int i = 0; i < basisBlades.Length; i++) { B[0][i] = basisBlades[i].GetBasisBlade; } return(B); }
/// <summary> /// Returns the group index of basis blade 'B' or -1 when not represented by this MV. /// /// Example: suppose you want to know the group and element index of B=e2^e3^no, /// then (assuming it is represented), it is in m_basisBlades[GetGroupIdx(B)][GetElementIdx(B)]. /// </summary> /// <param name="B">The basis blade whose bitmap is looked up.</param> /// <returns>-1 if 'B' is cannot be represented by this MV, otherwise, the index of the group.</returns> public int GetGroupIdx(RefGA.BasisBlade B) { if ((B.bitmap >= m_bitmapToGroup.Length) || (m_bitmapToGroup[B.bitmap] < 0)) { return(-1); } else { return(m_bitmapToGroup[B.bitmap] >> 16); } }
/// <summary> /// Returns the element index of basis blade 'B' or -1 when not represented by this MV. /// /// Example: suppose you want to know the group and element index of B=e2^e3^no, /// then (assuming it is represented), it is in BasisBlade(groupIdx, elemIdx). /// </summary> /// <param name="B">The basis blade whose bitmap is looked up.</param> /// <returns>-1 if 'B' is cannot be represented by this MV, otherwise, the index of the element in the group.</returns> public int GetElementIdx(RefGA.BasisBlade B) { if ((B.bitmap >= m_bitmapToGroup.Length) || (m_bitmapToGroup[B.bitmap] < 0)) { return(-1); } else { return(m_bitmapToGroup[B.bitmap] & 0xFFFF); } }
/// <summary> /// Constructor. Do not use directly. Use the constructors of G25.GMV and /// G25.SMV instead. /// /// If the multivector is specialized, basisBlades.Length must be 1. /// </summary> /// <param name="specialized">Whether this is a specialized MV or not.</param> /// <param name="name">The name of the multivector, for example "mv" or "rotor".</param> /// <param name="basisBlades">The basis blades, by group. Each entry in the array is a group of coordinates. /// Specialized multivector have only one group.</param> protected MV(bool specialized, String name, RefGA.BasisBlade[][] basisBlades) { if (specialized && (basisBlades.Length != 1)) { throw new Exception("G25.MV(): specialized multivector classes must have one group"); } m_specialized = specialized; m_name = name; m_basisBlades = new RefGA.BasisBlade[basisBlades.Length][]; for (int i = 0; i < basisBlades.Length; i++) { m_basisBlades[i] = (RefGA.BasisBlade[])basisBlades[i].Clone(); } { // init m_bitmapToGroup // get maximum dimension used in any of the basis blades: int maxDim = 0; for (int i = 0; i < m_basisBlades.Length; i++) { for (int j = 0; j < m_basisBlades[i].Length; j++) { int d = RefGA.Bits.HighestOneBit(m_basisBlades[i][j].bitmap); if (d > maxDim) { maxDim = d; } } } // allocate m_bitmapToGroup, set all to -1 m_bitmapToGroup = new int[1 << (maxDim + 1)]; for (int i = 0; i < m_bitmapToGroup.Length; i++) { m_bitmapToGroup[i] = -1; } // mark used position with group and element index for (int i = 0; i < m_basisBlades.Length; i++) { for (int j = 0; j < m_basisBlades[i].Length; j++) { m_bitmapToGroup[m_basisBlades[i][j].bitmap] = (i << 16) | j; } } } }
/// <summary> /// Returns highest grade basis blade in this MV. /// </summary> /// <returns>highest grade basis blade in this MV.</returns> public int HighestGrade() { int hg = -1; for (int g = 0; g < m_basisBlades.Length; g++) { for (int e = 0; e < m_basisBlades[g].Length; e++) { RefGA.BasisBlade srcB = m_basisBlades[g][e]; if (srcB.Grade() > hg) { hg = srcB.Grade(); } } } return(hg); }
/// <summary> /// Returns lowest grade basis blade in this MV. /// </summary> /// <returns>lowest grade basis blade in this MV.</returns> public int LowestGrade() { int lg = int.MaxValue; for (int g = 0; g < m_basisBlades.Length; g++) { for (int e = 0; e < m_basisBlades[g].Length; e++) { RefGA.BasisBlade srcB = m_basisBlades[g][e]; if (srcB.Grade() < lg) { lg = srcB.Grade(); } } } return(lg); }
/// <summary> /// Generates a map. For each coordinate in 'src', tells you where it is found in 'dst', /// or that it is not present. /// </summary> /// <param name="src">Src multivector (can be SMV or GMV).</param> /// <param name="dst">Dst multivector (can be SMV or GMV).</param> /// <returns>The first entry of each pair is the group, the second entry is the entry.</returns> public static Dictionary <Tuple <int, int>, Tuple <int, int> > GetCoordMap(MV src, MV dst) { Dictionary <Tuple <int, int>, Tuple <int, int> > D = new Dictionary <Tuple <int, int>, Tuple <int, int> >(); for (int g = 0; g < src.m_basisBlades.Length; g++) { for (int e = 0; e < src.m_basisBlades[g].Length; e++) { RefGA.BasisBlade srcB = src.m_basisBlades[g][e]; int groupIdx = dst.GetGroupIdx(srcB); if (groupIdx >= 0) { int elementIdx = dst.GetElementIdx(srcB); D[new Tuple <int, int>(g, e)] = new Tuple <int, int>(groupIdx, elementIdx); } } } return(D); }
/// <summary> /// This function takes the domain or range arrays (<c>RefGA.BasisBlade[][]</c>) /// and returns the basis vectors which span this domain or range. /// /// If <c>symbolicName</c> is not null, the vectors are given symbolic coordinates, /// <c>symbolicName0</c>, <c>symbolicName1</c>, and so on. /// </summary> /// <param name="D">The double array (typically domain or range of this OM)</param> /// <param name="symbolicName">Can be null. Optional symbolic coordinate base.</param> /// <returns></returns> protected static RefGA.BasisBlade[] GetVectors(RefGA.BasisBlade[][] D, string symbolicName) { // find out which vectors are in range, and create array of basis blades representing it as a vector type // get union of all bitmaps uint unionBitmap = 0; for (int g = 0; g < D.Length; g++) { for (int c = 0; c < D[g].Length; c++) { unionBitmap |= D[g][c].bitmap; } } // allocate memory for vectors uint nbVectors = RefGA.Bits.BitCount(unionBitmap); RefGA.BasisBlade[] vectors = new RefGA.BasisBlade[nbVectors]; // init vectors uint v = 1; int idx = 0; while (v <= unionBitmap) { if ((v & unionBitmap) != 0) { if (symbolicName == null) { vectors[idx] = new RefGA.BasisBlade(v); } else { vectors[idx] = new RefGA.BasisBlade(v, 1.0, symbolicName + idx); // note the symbolic coordinate (for easy FindTightestMatch()) } idx++; } v = v << 1; } return(vectors); }
/// <summary>Shortcut to ScalarProduct() </summary> public static BasisBlade scp(BasisBlade A, BasisBlade B, double[] m) { return ScalarProduct(A, B, m); }
/// <summary>Shortcut to ScalarProduct() </summary> public static ArrayList scp(BasisBlade A, BasisBlade B, Metric M) { return ScalarProduct(A, B, M); }
/// <summary> /// Returns the 'Hadamard product' of A and B. /// If A and B are the same basis blades up to scale, then multiplies /// the scalar parts of A and B with the unit basis blade. /// Otherwise returns 0. /// </summary> /// <param name="A">input blade.</param> /// <param name="B">input blade.</param> /// <returns>'Hadamard' product of A and B.</returns> public static BasisBlade HadamardProduct(BasisBlade A, BasisBlade B) { if (A.bitmap != B.bitmap) return BasisBlade.ZERO; uint bitmap = 0; B = new BasisBlade(B, bitmap); // get a copy of 'B', but as a scalar (0), so we can multiply the scalar part return BasisBlade.gp(A, B); }
/// <summary>Alternative way of calling B.GradeInvolution()</summary> public static BasisBlade GradeInvolution(BasisBlade B) { return B.GradeInvolution(); }
/// <summary> /// Shortcut to GeometricProduct() /// </summary> public static BasisBlade gp(BasisBlade a, BasisBlade b) { return GeometricProduct(a, b); }
/// <summary> /// Computes the inner product of two basis blades in Euclidean metric. /// </summary> /// <param name="A">input blade</param> /// <param name="B">input blade</param> /// <param name="m">an array of doubles giving the metric for each basis vector.</param> /// <param name="type">inner product type to be used. Use one of the InnerProductType constants: /// LEFT_CONTRACTION, RIGHT_CONTRACTION, HESTENES_INNER_PRODUCT, MODIFIED_HESTENES_INNER_PRODUCT or SCALAR_PRODUCT.</param> /// <returns>Inner product of <paramref name="A"/> and <paramref name="B"/>.</returns> public static BasisBlade InnerProduct(BasisBlade A, BasisBlade B, double[] m, InnerProductType type) { return InnerProductFilter(A.Grade(), B.Grade(), GeometricProduct(A, B, m), type); }
/// <summary> /// Shortcut to OuterProduct() /// </summary> public static BasisBlade op(BasisBlade a, BasisBlade b) { return OuterProduct(a, b); }
/// <summary> /// Transforms BasisBlade <paramref name="a"/> to the orthogonal basis of this metric. /// </summary> /// <param name="a">The BasisBlade (must be on the regular basis).</param> /// <returns><paramref name="a"/> on the new basis.</returns> public ArrayList ToEigenbasis(BasisBlade a) { return Transform(a, m_invEigMatrix); }
/// <summary>Shortcut to InnerProduct() </summary> public static ArrayList ip(BasisBlade A, BasisBlade B, Metric M, InnerProductType type) { return InnerProduct(A, B, M, type); }
/// <summary>Alternative way of calling B.Negate()</summary> public static BasisBlade Negate(BasisBlade B) { return B.Negate(); }
/// <summary>Shortcut to InnerProduct() </summary> public static BasisBlade ip(BasisBlade A, BasisBlade B, double[] m, InnerProductType type) { return InnerProduct(A, B, m, type); }
/// <summary> /// Returns the 'Inverse Hadamard product' of A and B. /// If A and B are the same basis blades up to scale, then divides /// the scalar part of A by the scalar part of B with the unit basis blade. /// Otherwise returns 0. /// /// Do not call when scale of B is zero (returned result will be zero). /// </summary> /// <param name="A">input blade.</param> /// <param name="B">input blade. Must not be zero.</param> /// <returns>'Inverse Hadamard' product of A and B.</returns> public static BasisBlade InverseHadamardProduct(BasisBlade A, BasisBlade B) { if (A.bitmap != B.bitmap) return BasisBlade.ZERO; uint bitmap = 0; if (B.IsSymbolic()) { B = new BasisBlade(B, bitmap); // get a copy of 'B', but as a scalar (0), so we can multiply the scalar part return BasisBlade.gp(A, new BasisBlade(0, 1.0, new Symbolic.UnaryScalarOp(Symbolic.UnaryScalarOp.INVERSE, new Multivector(B)))); } else { double newScale = (B.scale == 0.0) ? 0.0 : A.scale / B.scale; return new BasisBlade(A.bitmap, newScale, A.symScale); } }
/// <summary> /// Computes the inner product of two basis blades in Euclidean metric. /// </summary> /// <param name="A">input blade</param> /// <param name="B">input blade</param> /// <param name="M">The Metric to be used.</param> /// <param name="type">inner product type to be used. Use one of the InnerProductType constants: /// LEFT_CONTRACTION, RIGHT_CONTRACTION, HESTENES_INNER_PRODUCT, MODIFIED_HESTENES_INNER_PRODUCT or SCALAR_PRODUCT.</param> /// <returns>Inner product of <paramref name="A"/> and <paramref name="B"/>.</returns> public static ArrayList InnerProduct(BasisBlade A, BasisBlade B, Metric M, InnerProductType type) { return InnerProductFilter(A.Grade(), B.Grade(), GeometricProduct(A, B, M), type); }
/// <summary> /// Version of CompareTo() that also compares the symbolic scalar part (the standard CompareTo() does not do so) /// </summary> /// <param name="B">The object to which 'this' is compared</param> public int SymbolicCompareTo(BasisBlade B) { { // first do regular comparison: int c = CompareTo(B); if (c != 0) return c; } { // now try symbolic part: System.Collections.IComparer SSAC = new Util.SimplifySymbolicArrayComparer(); int l1 = (symScale == null) ? 0 : symScale.Length; int l2 = (B.symScale == null) ? 0 : B.symScale.Length; for (int i = 0; ((i < l1) && (i < l2)); i++) { // compare both arrays of scalar values: int c = SSAC.Compare(symScale[i], B.symScale[i]); if (c != 0) return c; // if not equal, we're done } // end of (one of the) arrays reached: compare length of arrays to make comparison return ((l1 < l2) ? -1 :((l1 > l2) ? 1 : 0)); } }
/// <summary> /// Little helper function for the constructor. /// </summary> /// <returns>'basisBlades', but inside a newly allocated array of length 1.</returns> protected static RefGA.BasisBlade[][] ToDoubleArray(RefGA.BasisBlade[] basisBlades) { RefGA.BasisBlade[][] B = new RefGA.BasisBlade[1][]; B[0] = basisBlades; return B; }
/// <summary> /// Transforms a basis blade to another basis which is represented by the columns of M. /// </summary> /// <param name="a">The basis blade to transform according to <paramref name="M"/>.</param> /// <param name="M">The matrix to use to transform <paramref name="a"/>.</param> /// <returns>a list of BasisBlade whose sum represents <paramref name="a"/> on the new basis.</returns> public static ArrayList Transform(BasisBlade a, DotNetMatrix.GeneralMatrix M) { ArrayList A = new ArrayList(); A.Add(new BasisBlade(0, a.scale, a.symScale)); // start with just the scalar part; int dim = M.RowDimension; // for each 1 bit: convert to list of blades int i = 0; uint b = a.bitmap; while (b != 0) { if ((b & 1) != 0) { // take column 'i' out of the matrix, wedge it to 'A' ArrayList tmp = new ArrayList(); for (int j = 0; j < dim; j++) { double m = M.GetElement(j, i); if (m != 0.0) { for (int k = 0; k < A.Count; k++) { BasisBlade o = BasisBlade.op((BasisBlade)A[k], new BasisBlade((uint)(1 << j), m)); if (o.scale != 0.0) tmp.Add(o); } } } A = tmp; } b >>= 1; i++; } return A; }
/// <summary>Computes the geometric product of two basis blades in arbitary non-Euclidean metric.</summary> /// <param name="_A">Basisblade</param> /// <param name="_B">Basisblade</param> /// <param name="M">Metric to be used</param> /// <returns>An ArrayList, because the result may not be a single BasisBlade anymore. For example, /// <c>no ni = no.ni + no^ni = -1 + no^ni</c>. </returns> public static ArrayList GeometricProduct(BasisBlade _A, BasisBlade _B, Metric M) { // convert arguments to 'eigenbasis' ArrayList A = M.ToEigenbasis(_A); ArrayList B = M.ToEigenbasis(_B); ArrayList result = new ArrayList(); double[] EM = M.EigenMetric; foreach (BasisBlade bA in A) foreach (BasisBlade bB in B) { BasisBlade C = GeometricProduct(bA, bB, EM); if (C.scale != 0.0) result.Add(C); } return M.ToMetricBasis(result); }
/// <summary> /// Transforms BasisBlade <paramref name="a"/> to the regular basis of this metric. /// </summary> /// <param name="a">The BasisBlade (must be on the orthogonal 'eigen' basis).</param> /// <returns><paramref name="a"/> on the new basis.</returns> public ArrayList ToMetricBasis(BasisBlade a) { return Transform(a, m_eig.GetV()); }
/// <summary> /// Returns the 'Hadamard' product of A and B. /// If A and B are the same basis blades up to scale, then multiplies /// the scalar parts of A and B with the unit basis blade. /// Otherwise returns 0. /// </summary> /// <param name="A">input blade.</param> /// <param name="B">input blade.</param> /// <returns>'Hadamard' product of A and B.</returns> public static BasisBlade hp(BasisBlade A, BasisBlade B) { return HadamardProduct(A, B); }
/// <summary>Computes the outer product of two basis blades.</summary> /// <returns>Outer product of two basis blades <paramref name="a"/> and <paramref name="b"/></returns> public static BasisBlade OuterProduct(BasisBlade a, BasisBlade b) { const bool outer = true; return gp_op(a, b, outer); }
/// <summary> /// Returns the 'Inverse Hadamard product' of A and B. /// If A and B are the same basis blades up to scale, then divides /// the scalar part of A by the scalar part of B with the unit basis blade. /// Otherwise returns 0. /// </summary> /// <param name="A">input blade.</param> /// <param name="B">input blade.</param> /// <returns>'Inverse Hadamard' product of A and B.</returns> public static BasisBlade ihp(BasisBlade A, BasisBlade B) { return InverseHadamardProduct(A, B); }
/// <summary> /// Little helper function for constructor. /// </summary> /// <returns>'basisBlades', but inside a newly allocated array of length 1.</returns> protected static RefGA.BasisBlade[][] ToDoubleArray(G25.rsbbp.BasisBlade[] basisBlades) { RefGA.BasisBlade[][] B = new RefGA.BasisBlade[1][]; B[0] = new RefGA.BasisBlade[basisBlades.Length]; for (int i = 0; i < basisBlades.Length; i++) B[0][i] = basisBlades[i].GetBasisBlade; return B; }
/// <summary>Alternative way of calling B.Reverse()</summary> public static BasisBlade Reverse(BasisBlade B) { return B.Reverse(); }
/// <summary>Computes the geometric product of two basis blades in diagonal non-Euclidean metric.</summary> /// <param name="a">Basisblade</param> /// <param name="b">Basisblade</param> /// <param name="m">array of doubles giving the metric for each basis vector (i.e., the diagonal of the diagonal metric matrix)</param> /// <returns>a new basis blade which is either the geometric product or the outer product of two basis blades <paramref name="a"/> and <paramref name="b"/>.</returns> public static BasisBlade GeometricProduct(BasisBlade a, BasisBlade b, double[] m) { // compute the geometric product in Euclidean metric: BasisBlade result = GeometricProduct(a, b); double resultScale = result.scale; // compute the meet (bitmap of annihilated vectors): uint bitmap = a.bitmap & b.bitmap; // change the scale according to the metric: uint i = 0; while (bitmap != 0) { if ((bitmap & 1) != 0) resultScale *= m[i]; i++; bitmap = bitmap >> 1; } // return correctly scaled result return new BasisBlade(result.bitmap, resultScale, result.symScale); }
/// <summary> /// Little helper function for the constructor. /// </summary> /// <returns>'basisBlades', but inside a newly allocated array of length 1.</returns> protected static RefGA.BasisBlade[][] ToDoubleArray(RefGA.BasisBlade[] basisBlades) { RefGA.BasisBlade[][] B = new RefGA.BasisBlade[1][]; B[0] = basisBlades; return(B); }
/// <summary>Computes the geometric product of two basis blades.</summary> /// <returns>geometric product of two basis blades <paramref name="a"/> and <paramref name="b"/></returns> public static BasisBlade GeometricProduct(BasisBlade a, BasisBlade b) { const bool outer = false; return gp_op(a, b, outer); }
/// <summary>Shortcut to ScalarProduct() </summary> public static BasisBlade scp(BasisBlade A, BasisBlade B) { return ScalarProduct(A, B); }
/// <summary> /// Computes the inner product of two basis blades in diagonal non-Euclidean metric. /// </summary> /// <param name="A">input blade</param> /// <param name="B">input blade</param> /// <param name="m">an array of doubles giving the metric for each basis vector</param> /// <returns>Scalar product of <paramref name="A"/> and <paramref name="B"/>.</returns> public static BasisBlade ScalarProduct(BasisBlade A, BasisBlade B, double[] m) { InnerProductType type = InnerProductType.SCALAR_PRODUCT; return InnerProductFilter(A.Grade(), B.Grade(), GeometricProduct(A, B, m), type); }
/// <summary>Shortcut to GeometricProduct()</summary> public static BasisBlade gp(BasisBlade a, BasisBlade b, double[] m) { return GeometricProduct(a, b, m); }
/// <summary> /// Computes the inner product of two basis blades in arbitary non-Euclidean metric. /// </summary> /// <param name="A">input blade</param> /// <param name="B">input blade</param> /// <param name="M">The Metric to be used</param> /// <returns>Scalar product of <paramref name="A"/> and <paramref name="B"/>.</returns> public static ArrayList ScalarProduct(BasisBlade A, BasisBlade B, Metric M) { InnerProductType type = InnerProductType.SCALAR_PRODUCT; return InnerProductFilter(A.Grade(), B.Grade(), GeometricProduct(A, B, M), type); }
/// <summary>Alternative way of calling B.CliffordConjugate()</summary> public static BasisBlade CliffordConjugate(BasisBlade B) { return B.CliffordConjugate(); }