/// <param name="S"></param> /// <param name="FT"></param> /// <param name="M"></param> /// <param name="d">1 -> generate dual, d = 0 -> generate undual</param> /// <param name="g1"></param> /// <param name="gd"></param> /// <param name="name1"></param> /// <param name="name2"></param> /// <param name="name3"></param> /// <returns>The code to compute a (un)dual at runtime using the geometric product tables.</returns> public static string GetRuntimeDualCode(G25.Specification S, G25.FloatType FT, G25.Metric M, int d, int g1, int gd, string name1, string name2, string name3) { // get pseudoscalar RefGA.Multivector I = RefGA.Multivector.GetPseudoscalar(S.m_dimension); if (d == 1) // if dual: use inverse I { I = RefGA.Multivector.VersorInverse(I, M.m_metric); } // get grade/group of pseudoscalar in GMV int g2 = S.m_GMV.GetGroupIdx(I.BasisBlades[0]); // get sign of pseudo scalar basis blade in GMV: double IbladeSign = S.m_GMV.Group(g2)[0].scale; string tmpArrayCode; if (S.OutputCppOrC()) { tmpArrayCode = "\t" + FT.type + " " + name2 + "[1] = {" + FT.DoubleToString(S, IbladeSign * I.BasisBlades[0].scale) + "};\n"; } else { tmpArrayCode = "\t\t" + FT.type + "[] " + name2 + " = new " + FT.type + "[]{" + FT.DoubleToString(S, IbladeSign * I.BasisBlades[0].scale) + "};\n\t"; } return (tmpArrayCode + "\t" + GPparts.GetGPpartFunctionName(S, FT, M, g1, g2, gd) + "(" + name1 + ", " + name2 + ", " + name3 + ");\n"); }
} // end of WriteGMVtoSMVcopy() private static void WriteCoordExtractFunction(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, string gmvTypeName, int groupIdx, int elementIdx, RefGA.BasisBlade B) { StringBuilder declSB = cgd.m_declSB; StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; String bladeName = B.ToLangString(S.m_basisVectorNames); string varName = "A"; // do we inline this func? string inlineStr = G25.CG.Shared.Util.GetInlineString(S, S.m_inlineSet, " "); string funcName = gmvTypeName + "_" + bladeName; string funcDecl = inlineStr + FT.type + " " + funcName + "(const " + gmvTypeName + " *" + varName + ")"; string comment = "/** Returns the " + B.ToString(S.m_basisVectorNames) + " coordinate of '" + varName + "' */"; // declSB.AppendLine("/* group : " + groupIdx + " element: " + elementIdx + "*/"); declSB.AppendLine(comment); declSB.Append(funcDecl); declSB.AppendLine(";"); defSB.AppendLine(""); defSB.Append(funcDecl); defSB.AppendLine(" {"); defSB.AppendLine("\treturn (" + varName + "->gu & " + (1 << groupIdx) + ") ? " + varName + "->c[" + S.m_namespace + "_mvSize[" + varName + "->gu & " + ((1 << groupIdx) - 1) + "] + " + elementIdx + "] : " + FT.DoubleToString(S, 0.0) + ";"); defSB.AppendLine("}"); // add extract coord extract function for scalar if (B.Grade() == 0) { string floatFuncName = gmvTypeName + "_" + FT.type; string floatFuncDecl = inlineStr + FT.type + " " + floatFuncName + "(const " + gmvTypeName + " *" + varName + ")"; declSB.AppendLine(comment); declSB.Append(floatFuncDecl); declSB.AppendLine(";"); defSB.Append(floatFuncDecl); defSB.AppendLine(" {"); defSB.AppendLine("\treturn " + funcName + "(" + varName + ");"); defSB.AppendLine("}"); } }
private static void WriteGetCoordFunction(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, StringBuilder SB, string gmvTypeName, int groupIdx, int elementIdx, RefGA.BasisBlade B) { String bladeName = B.ToLangString(S.m_basisVectorNames); // do we inline this func? string inlineStr = "inline "; string funcName = MainGenerator.GETTER_PREFIX + bladeName; string funcDecl = "\t" + inlineStr + FT.type + " " + funcName + "() const"; SB.AppendLine("\t/// Returns the " + bladeName + " coordinate of this " + gmvTypeName + "."); SB.Append(funcDecl); SB.AppendLine(" {"); SB.AppendLine("\t\treturn (m_gu & " + (1 << groupIdx) + ") ? " + "m_c[" + S.m_namespace + "_mvSize[m_gu & " + ((1 << groupIdx) - 1) + "] + " + elementIdx + "] : " + FT.DoubleToString(S, 0.0) + ";"); SB.AppendLine("\t}"); }
} // end of WriteGMVtoSMVcopy() private static void WriteGetCoordFunction(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, string gmvTypeName, int groupIdx, int elementIdx, RefGA.BasisBlade B) { string bladeName = B.ToLangString(S.m_basisVectorNames); string funcName = G25.CG.Shared.Main.GETTER_PREFIX + bladeName; string funcDecl = "\t" + Keywords.PublicAccessModifier(S) + " " + FT.type + " " + funcName + "() "; int nbTabs = 1; new G25.CG.Shared.Comment("Returns the " + bladeName + " coordinate of this " + gmvTypeName).Write(SB, S, nbTabs); SB.Append(funcDecl); SB.AppendLine(" {"); SB.AppendLine("\t\treturn (m_c[" + groupIdx + "] == null) ? " + FT.DoubleToString(S, 0.0) + ": " + "m_c[" + groupIdx + "][" + elementIdx + "];"); SB.AppendLine("\t}"); }
/// <summary> /// Writes a function to set an GOM struct to identity, for all floating point types. /// </summary> /// <param name="SB">Where the code goes.</param> /// <param name="S">Used for basis vector names and output language.</param> /// <param name="cgd">Results go here. Also intermediate data for code generation. Also contains plugins and cog.</param> /// <param name="FT">Float point type of 'GOM'.</param> public static void WriteSetIdentity(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT) { SB.AppendLine(""); string omName = "a"; string matrixName = "m_m"; // todo: centralize this name Dictionary <double, List <string> > nonZero = G25.CG.Shared.OMinit.GetGomIdentityInitCode(S, S.m_GOM, omName, matrixName); //string className = FT.GetMangledName(S, S.m_GOM.Name); string funcName = Util.GetFunctionName(S, "setIdentity"); SB.AppendLine("\t" + Keywords.PublicAccessModifier(S) + " void " + funcName + "() {"); for (int g = 1; g < S.m_GOM.Domain.Length; g++) { int s = S.m_GOM.Domain[g].Length * S.m_GOM.Range[g].Length; SB.AppendLine("\t\t" + G25.CG.Shared.Util.GetSetToZeroCode(S, FT, matrixName + g, s)); } // end of loop over all grades of the OM // do the nonZero assignments: foreach (KeyValuePair <double, List <string> > kvp in nonZero) { SB.Append("\t\t"); int cnt = 0; foreach (string coordStr in kvp.Value) { SB.Append(coordStr + " = "); cnt++; if ((cnt % 8) == 0) { SB.Append("\n\t\t\t"); } } SB.AppendLine(FT.DoubleToString(S, kvp.Key) + ";"); } SB.AppendLine("\t}"); } // end of WriteSetIdentity()
/// <summary> /// Converts a scalar basis blade (with optional symbolic part) to a string in the output language of <c>S</c>. /// /// Some effort is made to output code which is close to that a human would write. /// </summary> /// <param name="S">Specification of algebra, used for output language, basis vector names, etc.</param> /// <param name="FT">Floating point type of output.</param> /// <param name="B">The basis blade.</param> /// <returns>String code representation of 'B'.</returns> public static string ScalarToLangString(G25.Specification S, G25.FloatType FT, RefGA.BasisBlade B) { string symScaleStr = ""; { // convert symbolic part if (B.symScale != null) { // symbolic scalar string goes in symResult System.Text.StringBuilder symResult = new System.Text.StringBuilder(); int tCnt = 0; for (int t = 0; t < B.symScale.Length; t++) // for each term ...*...*...+ { Object[] T = (Object[])B.symScale[t].Clone(); // clone 'T' because IsolateInverses() might alter it! if (T != null) // if term is not null { // first find all scalarop inverses // turn those into a new term, but without inverses? Object[] TI = IsolateInverses(T); // emit 'T' int pCnt = EmitTerm(S, FT, T, tCnt, symResult); if (TI != null) // do we have to divide by a number of terms? { // emit '/(TI)' symResult.Append("/("); EmitTerm(S, FT, TI, 0, symResult); symResult.Append(")"); } if (pCnt > 0) { tCnt++; // only increment number of terms when T was not empty } } } if (tCnt > 0) { symScaleStr = ((tCnt > 1) ? "(" : "") + symResult + ((tCnt > 1) ? ")" : ""); } } } // end of symbolic part // special cases when numerical scale is exactly +- 1 if (B.scale == 1.0) { if (symScaleStr.Length > 0) { return(symScaleStr); } else { return(FT.DoubleToString(S, 1.0)); } } else if (B.scale == -1.0) { if (symScaleStr.Length > 0) { return("-" + symScaleStr); } else { return(FT.DoubleToString(S, -1.0)); } } else { // get numerical part string numScaleStr = FT.DoubleToString(S, B.scale); // merge symbolic and numerical if (symScaleStr.Length > 0) { numScaleStr = numScaleStr + "*" + symScaleStr; } // done return(numScaleStr); } } // end of function ScalarToLangString
} // end of GetAssignmentStrings() /// <summary> /// Used internally by ScalarToLangString(). /// /// Emits on term (+ ....) of a blade value. Contains some optimizations /// to avoid stuff like <c>+-1.0</c>. /// </summary> protected static int EmitTerm(G25.Specification S, G25.FloatType FT, Object[] T, int tCnt, StringBuilder symResult) { // make stuff below a function bool plusEmitted = false; int pCnt = 0; // number of non-null terms in 'T' for (int p = 0; p < T.Length; p++) // for each product ...* { if (T[p] != null) { if ((!plusEmitted) && (tCnt > 0)) { symResult.Append("+"); plusEmitted = true; } if ((pCnt > 0) && (symResult.Length > 0) && (!((symResult[symResult.Length - 1] == '-') || (symResult[symResult.Length - 1] == '+')))) { symResult.Append("*"); } System.Object O = T[p]; if ((O is System.Double) || (O is System.Single) || (O is System.Int16) || (O is System.Int32) || (O is System.Int64)) // etc . . . (all number types) { double val = (double)O; if ((val == -1.0) && (p == 0) && (T.Length > 1)) { // when multiplying with -1.0, output only a '-', IF the term is the first (p==0) and more terms follow (T.Length > 1) if (symResult.Length > 0) { // when val = -1, output code which is better for humans, instead of -1.0 * ... if (symResult[symResult.Length - 1] == '+') // change '+' to '-' { symResult[symResult.Length - 1] = '-'; } else { symResult.Append("-"); } } else { symResult.Append("-"); } } else if ((val == 1.0) && (p == 0) && (T.Length > 1)) { // when multiplying with 1.0, output nothing IF the term is the first (p==0) and more terms follow (T.Length > 1) // do nothing } else { symResult.Append(FT.DoubleToString(S, (double)O)); } } else if (O is UnaryScalarOp) { UnaryScalarOp USO = (UnaryScalarOp)O; symResult.Append(UnaryScalarOpToLangString(S, FT, USO)); } else if (O is BinaryScalarOp) { BinaryScalarOp BSO = (BinaryScalarOp)O; symResult.Append(BinaryScalarOpToLangString(S, FT, BSO)); } else if (O is RefGA.BasisBlade) { symResult.Append(ScalarToLangString(S, FT, (RefGA.BasisBlade)O)); } else if (O is RefGA.Multivector) { RefGA.Multivector mv = (RefGA.Multivector)O; StringBuilder mvSB = new StringBuilder(); mvSB.Append("("); bool first = true; foreach (RefGA.BasisBlade B in mv.BasisBlades) { if (!first) { mvSB.Append(" + "); } first = false; mvSB.Append(ScalarToLangString(S, FT, B)); } mvSB.Append(")"); symResult.Append(mvSB); } else { symResult.Append(O.ToString()); } pCnt++; } } return(pCnt); }
} // end of WriteSetVectorImages() private static void WriteOMtoOMcopy(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, OM srcOm, OM dstOm) { StringBuilder declSB = cgd.m_declSB; StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; string srcTypeName = FT.GetMangledName(S, srcOm.Name); string dstTypeName = FT.GetMangledName(S, dstOm.Name); // write comment declSB.AppendLine("/** Copies a " + srcTypeName + " to a " + dstTypeName); declSB.AppendLine(" * Warning 1: coordinates which cannot be represented are silenty lost"); declSB.AppendLine(" * Warning 2: coordinates which are not present in 'src' are set to zero in 'dst'."); declSB.AppendLine(" */"); string funcName = srcTypeName + "_to_" + dstTypeName; // do we inline this func? string inlineStr = G25.CG.Shared.Util.GetInlineString(S, S.m_inlineSet, " "); string funcDecl = inlineStr + "void " + funcName + "(" + dstTypeName + " *dst, const " + srcTypeName + " *src)"; declSB.Append(funcDecl); declSB.AppendLine(";"); defSB.Append(funcDecl); { defSB.AppendLine(" {"); Dictionary <Tuple <int, int, int>, Tuple <int, int, double> > D = dstOm.getMapping(srcOm); StringBuilder copySB = new StringBuilder(); List <string> setToZero = new List <string>(); // For all grades of som, for all columns, for all rows, check D, get entry, set; otherwise set to null // Do not use foreach() on D because we want to fill in coordinates in their proper order. for (int gradeIdx = 1; gradeIdx < dstOm.Domain.Length; gradeIdx++) { for (int somRangeIdx = 0; somRangeIdx < dstOm.Range[gradeIdx].Length; somRangeIdx++) { for (int somDomainIdx = 0; somDomainIdx < dstOm.Domain[gradeIdx].Length; somDomainIdx++) { Tuple <int, int, int> key = new Tuple <int, int, int>(gradeIdx, somDomainIdx, somRangeIdx); int somMatrixIdx = dstOm.getCoordinateIndex(gradeIdx, somDomainIdx, somRangeIdx); string dstString = "dst->m" + gradeIdx + "[" + somMatrixIdx + "] = "; if (D.ContainsKey(key)) { Tuple <int, int, double> value = D[key]; int gomMatrixIdx = srcOm.getCoordinateIndex(gradeIdx, value.Value1, value.Value2); double multiplier = value.Value3; string multiplierString = (multiplier == 1.0) ? "" : (FT.DoubleToString(S, multiplier) + " * "); copySB.AppendLine("\t" + dstString + multiplierString + " src->m" + gradeIdx + "[" + gomMatrixIdx + "];"); } else { setToZero.Add(dstString); } } } } // append copy statements defSB.Append(copySB); // append statements to set coordinates to zero if (setToZero.Count > 0) { int cnt = 0; defSB.Append("\t"); foreach (string str in setToZero) { defSB.Append(str); cnt++; if (cnt > 8) { cnt = 0; defSB.AppendLine(""); defSB.Append("\t\t"); } } defSB.AppendLine(FT.DoubleToString(S, 0.0) + ";"); } defSB.AppendLine("}"); } }
} // end of WriteGMVtoSMVcopy() /// <summary> /// Writes code for abs largest coordinate /// </summary> /// <param name="S"></param> /// <param name="cgd">Results go here. Also intermediate data for code generation. Also contains plugins and cog.</param> public static void WriteLargestCoordinateFunctions(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.SMV smv) { StringBuilder defSB = cgd.m_defSB; defSB.AppendLine(""); const string smvName = G25.CG.Shared.SmvUtil.THIS; const bool ptr = false; string fabsFunc = G25.CG.Shared.CodeUtil.OpNameToLangString(S, FT, RefGA.Symbolic.UnaryScalarOp.ABS); string[] AS = G25.CG.Shared.CodeUtil.GetAccessStr(S, smv, smvName, ptr); RefGA.BasisBlade maxBasisBlade = smv.AbsoluteLargestConstantBasisBlade(); //string className = FT.GetMangledName(S, smv.Name); for (int _returnBitmap = 0; _returnBitmap <= 1; _returnBitmap++) { bool returnBitmap = (_returnBitmap != 0); // write comment int nbTabs = 1; if (returnBitmap) { new G25.CG.Shared.Comment("Returns the absolute largest coordinate,\nand the corresponding basis blade bitmap.").Write(defSB, S, nbTabs); } else { new G25.CG.Shared.Comment("Returns the absolute largest coordinate.").Write(defSB, S, nbTabs); } string funcName = Util.GetFunctionName(S, ((returnBitmap) ? "largestBasisBlade" : "largestCoordinate")); string funcDecl; if ((S.OutputCSharp()) && returnBitmap) { funcDecl = FT.type + " " + funcName + "(int bm) "; } else if ((S.OutputJava()) && returnBitmap) { funcDecl = FT.type + "[] " + funcName + "() "; } else { funcDecl = FT.type + " " + funcName + "()"; } string FINAL = (S.OutputJava()) ? "final " : ""; defSB.Append("\tpublic " + FINAL + funcDecl); { defSB.AppendLine(" {"); if ((S.OutputJava()) && returnBitmap) { defSB.AppendLine("\t\tint bm;"); } int startIdx = 0; if (maxBasisBlade != null) { defSB.AppendLine("\t\t" + FT.type + " maxValue = " + FT.DoubleToString(S, Math.Abs(maxBasisBlade.scale)) + ";"); if (returnBitmap) { defSB.AppendLine("\t\tbm = " + maxBasisBlade.bitmap + ";"); } } else { defSB.AppendLine("\t\t" + FT.type + " maxValue = " + fabsFunc + "(" + AS[0] + ");"); if (returnBitmap) { defSB.AppendLine("\t\tbm = 0;"); } startIdx = 1; } for (int c = startIdx; c < smv.NbNonConstBasisBlade; c++) { defSB.Append("\t\tif (" + fabsFunc + "(" + AS[c] + ") > maxValue) { maxValue = " + fabsFunc + "(" + AS[c] + "); "); if (returnBitmap) { defSB.Append("bm = " + smv.NonConstBasisBlade(c).bitmap + "; "); } defSB.AppendLine("}"); } if ((S.OutputJava()) && returnBitmap) { defSB.AppendLine("\t\treturn new " + FT.type + "[]{maxValue, (" + FT.type + ")bm};"); } else { defSB.AppendLine("\t\treturn maxValue;"); } defSB.AppendLine("\t}"); } } } // end of WriteLargestCoordinateFunctions()
} // end of WriteSetCopyCrossFloat() /// <summary> /// Writes functions to copy GMVs to SMVs /// </summary> /// <param name="S"></param> /// <param name="cgd">Results go here. Also intermediate data for code generation. Also contains plugins and cog.</param> public static void WriteGMVtoSMVcopy(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.SMV smv) { StringBuilder defSB = cgd.m_defSB; G25.GMV gmv = S.m_GMV; string srcClassName = FT.GetMangledName(S, gmv.Name); //string dstClassName = FT.GetMangledName(S, smv.Name); bool dstPtr = false; string[] smvAccessStr = G25.CG.Shared.CodeUtil.GetAccessStr(S, smv, G25.CG.Shared.SmvUtil.THIS, dstPtr); string funcName = GMV.GetSetFuncName(S); string FINAL = (S.OutputJava()) ? "final " : ""; string funcDecl = "\tpublic " + FINAL + "void " + funcName + "(" + FINAL + srcClassName + " src)"; defSB.Append(funcDecl); { defSB.AppendLine(" {"); // get a dictionary which tells you for each basis blade of 'smv' where it is in 'gmv' // A dictionary from <smv group, smv element> to <gmv group, gmv element> Dictionary <Tuple <int, int>, Tuple <int, int> > D = G25.MV.GetCoordMap(smv, gmv); // what is the highest group of the 'gmv' that must be (partially) copied to the 'smv' int highestGroup = -1; foreach (KeyValuePair <Tuple <int, int>, Tuple <int, int> > KVP in D) { if (KVP.Value.Value1 > highestGroup) { highestGroup = KVP.Value.Value1; } } // generate code for each group for (int g = 0; g <= highestGroup; g++) { // determine if group 'g' is to be copied to smv: bool groupIsUsedBySMV = false; foreach (KeyValuePair <Tuple <int, int>, Tuple <int, int> > KVP in D) { // KVP.Key = SMV<group, element> // KVP.Value = GMV<group, element> if (KVP.Value.Value1 == g) { if (!smv.IsCoordinateConstant(KVP.Key.Value2)) { groupIsUsedBySMV = true; break; } } } // if group is present in GMV: if (groupIsUsedBySMV) { defSB.AppendLine("\t\tif (src.c()[" + g + "] != null) {"); defSB.AppendLine("\t\t\t" + FT.type + "[] ptr = src.c()[" + g + "];"); bool mustCast = false; bool srcPtr = true; int nbTabs = 3; RefGA.Multivector[] value = G25.CG.Shared.Symbolic.GMVtoSymbolicMultivector(S, gmv, "ptr", srcPtr, g); bool writeZeros = false; string str = G25.CG.Shared.CodeUtil.GenerateSMVassignmentCode(S, FT, mustCast, smv, G25.CG.Shared.SmvUtil.THIS, dstPtr, value[g], nbTabs, writeZeros); defSB.Append(str); defSB.AppendLine("\t\t}"); defSB.AppendLine("\t\telse {"); foreach (KeyValuePair <Tuple <int, int>, Tuple <int, int> > KVP in D) { if ((KVP.Value.Value1 == g) && (!smv.IsCoordinateConstant(KVP.Key.Value2))) { // translate KVP.Key.Value2 to non-const idx, because the accessStrs are only about non-const blades blades! int bladeIdx = smv.BladeIdxToNonConstBladeIdx(KVP.Key.Value2); defSB.AppendLine("\t\t\t" + smvAccessStr[bladeIdx] + " = " + FT.DoubleToString(S, 0.0) + ";"); } } defSB.AppendLine("\t\t}"); } } defSB.AppendLine("\t}"); } } // end of WriteGMVtoSMVcopy()