public static void GenerateBasisElementsArray(Specification S, G25.CG.Shared.CGdata cgd, StringBuilder SB) { G25.GMV gmv = S.m_GMV; // basis vectors in basis elements SB.AppendLine("const int " + S.m_namespace + "_basisElements[" + (1 << S.m_dimension) + "][" + (S.m_dimension + 1) + "] = {"); { bool comma = false; for (int i = 0; i < gmv.NbGroups; i++) { for (int j = 0; j < gmv.Group(i).Length; j++) { if (comma) { SB.Append(",\n"); } RefGA.BasisBlade B = gmv.Group(i)[j]; SB.Append("\t{"); for (int k = 0; k < S.m_dimension; k++) { if ((B.bitmap & (1 << k)) != 0) { SB.Append(k + ", "); } } SB.Append("-1}"); comma = true; } } } SB.AppendLine(""); SB.AppendLine("};"); }
} // end of GetAccessStr() /// <summary> /// Returns an array of 'access strings' for a specific group of the general multivector. /// Access strings are source code expressions that can be /// used to access the coordinates of one specific group of coordinates of <c>gmv</c>. /// </summary> /// <param name="S">Used for basis blade names, language, COORD_STORAGE , etc.</param> /// <param name="gmv">The specialized multivector for which access strings are generated.</param> /// <param name="gmvName">The variable name of the _array_ of float to be used in the access strings. /// For example, specify <c>"A"</c> to get <c>"A[0]"</c> and so on.</param> /// <param name="groupIdx">Specifies for that group index the access strings should be generated.</param> /// <param name="baseIdx">Index of first coordinate of group (required for C# and Java)</param> /// <returns>Array of strings that can be used to access the coordinates of group <c>groupIdx</c> of the <c>gmv</c>.</returns> public static string[] GetAccessStr(Specification S, G25.GMV gmv, String gmvName, int groupIdx, int baseIdx) { string[] AL = new String[gmv.Group(groupIdx).Length]; for (int i = 0; i < gmv.Group(groupIdx).Length; i++) { AL[i] = gmvName + "[" + (baseIdx + i) + "]"; } return(AL); } // end of GetAccessStr()
public static void GenerateMultivectorSizeArray(Specification S, G25.CG.Shared.CGdata cgd, StringBuilder SB) { G25.GMV gmv = S.m_GMV; // size of multivector based on grade usage bitmap SB.AppendLine("const int " + S.m_namespace + "_mvSize[" + (1 << gmv.NbGroups) + "] = {"); SB.Append("\t"); for (int i = 0; i < (1 << gmv.NbGroups); i++) { int s = 0; for (int j = 0; j < gmv.NbGroups; j++) { if ((i & (1 << j)) != 0) { s += gmv.Group(j).Length; } } SB.Append(s); if (i != ((1 << gmv.NbGroups) - 1)) { SB.Append(", "); } if ((i % 20) == 19) { SB.AppendLine(""); SB.Append("\t"); } } SB.AppendLine("};"); }
private static void GenerateMultivectorSizeArrayInit(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd) { string accessModifierArr = Keywords.ConstArrayAccessModifier(S); G25.GMV gmv = S.m_GMV; // size of multivector based on grade usage bitmap SB.AppendLine("\tpublic " + accessModifierArr + " int[] MvSize = new int[] {"); SB.Append("\t\t"); for (int i = 0; i < (1 << gmv.NbGroups); i++) { int s = 0; for (int j = 0; j < gmv.NbGroups; j++) { if ((i & (1 << j)) != 0) { s += gmv.Group(j).Length; } } SB.Append(s); if (i != ((1 << gmv.NbGroups) - 1)) { SB.Append(", "); } if ((i % 20) == 19) { SB.AppendLine(""); SB.Append("\t\t"); } } SB.AppendLine("\t};"); }
/// <summary> /// Takes a general multivector specification (G25.GMV) and converts it into a one symbolic multivector per group/grade part. /// /// The symbolic weights of the multivector are the coordinates of the GMV, labelled according to 'gmvName'. /// Currently, the indices start at zero for each group. /// </summary> /// <param name="S">Specification of the algebra. Used for the access convention (. or ->) and for how to name the coordinates ([0] or e1, e2, e3).</param> /// <param name="gmv">The specification of the general multivector.</param> /// <param name="gmvName">Name the variable should have.</param> /// <param name="ptr">Is 'gmvName' a pointer? (not used currently)</param> /// <param name="groupIdx">Index of group/grade to convert (use -1 for all groups)</param> /// <returns></returns> public static RefGA.Multivector[] GMVtoSymbolicMultivector(Specification S, G25.GMV gmv, String gmvName, bool ptr, int groupIdx) { RefGA.Multivector[] R = new RefGA.Multivector[gmv.NbGroups]; //String accessStr = (ptr) ? "->" : "."; for (int g = 0; g < gmv.NbGroups; g++) { if ((groupIdx >= 0) && (g != groupIdx)) { continue; // only one group requested? } RefGA.BasisBlade[] B = gmv.Group(g); RefGA.BasisBlade[] L = new RefGA.BasisBlade[B.Length]; for (int i = 0; i < B.Length; i++) { RefGA.BasisBlade b = B[i]; String fullCoordName = gmvName + "[" + i + "]"; // merge L[i] = new RefGA.BasisBlade(b.bitmap, b.scale, fullCoordName); } R[g] = new RefGA.Multivector(L); } return(R); } // end of function GMVtoSymbolicMultivector()
public static void GenerateBasisElementsArray(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd) { string accessModifierArr = Keywords.ConstArrayAccessModifier(S); G25.GMV gmv = S.m_GMV; // basis vectors in basis elements new G25.CG.Shared.Comment("This array of integers contains the order of basis elements in the general multivector.\n" + "Use it to answer: 'what basis vectors are in the basis element at position [x]?").Write(SB, S, 1); SB.Append("\tpublic " + accessModifierArr + " int[][] BasisElements = "); if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) { SB.AppendLine("new int[][] {"); { bool comma = false; for (int i = 0; i < gmv.NbGroups; i++) { for (int j = 0; j < gmv.Group(i).Length; j++) { if (comma) { SB.Append(",\n"); } RefGA.BasisBlade B = gmv.Group(i)[j]; SB.Append("\t\tnew int[] {"); for (int k = 0; k < S.m_dimension; k++) { if ((B.bitmap & (1 << k)) != 0) { SB.Append(k + ", "); } } SB.Append("-1}"); comma = true; } } } SB.AppendLine(""); SB.AppendLine("\t};"); } else { SB.AppendLine(G25.CG.CSJ.Util.GetFunctionName(S, "initBasisElementsArray") + "();"); SB.AppendLine(); cgd.m_cog.EmitTemplate(SB, "initBasisElementsArray", "S=", S); } }
} // end of GenerateSMVassignmentCode /// <summary> /// Generates the code to assign a multivector value (which may have symbolic coordinates) to one specific coordinate group of a multivector. /// </summary> /// <param name="S">Specification of algebra. Used to known names of basis vector, output language, access strings, etc.</param> /// <param name="FT">Floating point type of destination.</param> /// <param name="mustCast">set to true if a cast to 'FT' must be performed before assigned to 'dstName'.</param> /// <param name="dstGmv">Type of general multivector assigned to.</param> /// <param name="dstName">Name of specialized multivector assigned to.</param> /// <param name="dstGroupIdx">Write to which group in destination type?</param> /// <param name="dstBaseIdx">Base index of coordinate 0 of group (needed for C# and Java)</param> /// <param name="value">Multivector value to assign to the GMV. Must not contain basis blades inside the symbolic scalars.</param> /// <param name="nbTabs">Number of tabs to put before the code.</param> /// <param name="writeZeros">Some callers want to skip "= 0.0" assignments because they would be redundant. So they set this argument to true.</param> /// <returns>String of code for dstName = value;</returns> public static string GenerateGMVassignmentCode(Specification S, FloatType FT, bool mustCast, G25.GMV dstGmv, string dstName, int dstGroupIdx, int dstBaseIdx, RefGA.Multivector value, int nbTabs, bool writeZeros) { RefGA.BasisBlade[] BL = dstGmv.Group(dstGroupIdx); string[] accessStr = GetAccessStr(S, dstGmv, dstName, dstGroupIdx, dstBaseIdx); string[] assignedStr = GetAssignmentStrings(S, FT, mustCast, BL, value, writeZeros); return(GenerateAssignmentCode(S, accessStr, assignedStr, nbTabs, writeZeros)); } // end of GenerateSMVassignmentCode
/// <summary> /// Returns the comment for a GMV class. /// </summary> /// <param name="S">Used for basis vector names and output language.</param> /// <param name="cgd">Intermediate data for code generation. Also contains plugins and cog.</param> /// <param name="FT">Float point type of 'GMV'.</param> /// <param name="gmv">The general multivector for which the class should be written.</param> public static Comment GetGmvComment(Specification S, G25.CG.Shared.CGdata cgd, FloatType FT, G25.GMV gmv) { StringBuilder SB = new StringBuilder(); SB.AppendLine("This class can hold a general multivector."); SB.AppendLine(""); SB.AppendLine("The coordinates are stored in type " + FT.type + "."); SB.AppendLine(""); SB.AppendLine("There are " + gmv.NbGroups + " coordinate groups:"); for (int g = 0; g < gmv.NbGroups; g++) { SB.Append("group " + g + ":"); for (int i = 0; i < gmv.Group(g).Length; i++) { if (i > 0) SB.Append(", "); SB.Append(gmv.Group(g)[i].ToString(S.m_basisVectorNames)); } if (gmv.Group(g).Length > 0) SB.Append(" (grade " + gmv.Group(g)[0].Grade() + ")"); SB.AppendLine("."); } SB.AppendLine(""); switch (S.m_GMV.MemoryAllocationMethod) { case G25.GMV.MEM_ALLOC_METHOD.PARITY_PURE: SB.AppendLine("" + (gmv.NbCoordinates / 2) + " " + FT.type + "s are allocated inside the struct ('parity pure')."); SB.AppendLine("Hence creating a multivector which needs more than that number of coordinates "); SB.AppendLine("will result in unpredictable behaviour (buffer overflow)."); break; case G25.GMV.MEM_ALLOC_METHOD.FULL: SB.AppendLine("" + gmv.NbCoordinates + " " + FT.type + "s are allocated inside the struct."); break; } return new Comment(SB.ToString()); } // end of GetGmvComment()
/// <summary> /// Writes functions to set coordinates of the GMV /// </summary> /// <param name="S"></param> /// <param name="cgd">Results go here. Also intermediate data for code generation. Also contains plugins and cog.</param> /// <param name="FT"></param> /// <param name="SB"></param> public static void WriteSetCoord(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, StringBuilder SB) { G25.GMV gmv = S.m_GMV; string typeName = FT.GetMangledName(S, gmv.Name); for (int groupIdx = 0; groupIdx < gmv.NbGroups; groupIdx++) { for (int elementIdx = 0; elementIdx < gmv.Group(groupIdx).Length; elementIdx++) { WriteSetCoordFunction(S, cgd, FT, SB, typeName, groupIdx, elementIdx, gmv.Group(groupIdx).Length, gmv.Group(groupIdx)[elementIdx]); } } }
/// <summary> /// Writes functions to extract coordinates from the GMV /// </summary> /// <param name="S"></param> /// <param name="cgd">Results go here. Also intermediate data for code generation. Also contains plugins and cog.</param> /// <param name="FT"></param> /// <param name="SB"></param> public static void WriteGetCoord(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, StringBuilder SB) { G25.GMV gmv = S.m_GMV; string typeName = FT.GetMangledName(S, gmv.Name); for (int groupIdx = 0; groupIdx < gmv.NbGroups; groupIdx++) { for (int elementIdx = 0; elementIdx < gmv.Group(groupIdx).Length; elementIdx++) { WriteGetCoordFunction(S, cgd, FT, SB, typeName, groupIdx, elementIdx, gmv.Group(groupIdx)[elementIdx]); } } SB.AppendLine("\t/// Returns array of compressed coordinates."); SB.AppendLine("\tinline const " + FT.type + " *getC() const { return m_c;}"); }
/// <summary> /// Writes functions to reserve a coordinate group /// </summary> /// <param name="S"></param> /// <param name="cgd"></param> public static void WriteReserveGroups(Specification S, G25.CG.Shared.CGdata cgd) { //StringBuilder declSB = cgd.m_declSB; //StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; G25.GMV gmv = S.m_GMV; foreach (G25.FloatType FT in S.m_floatTypes) { string typeName = FT.GetMangledName(S, gmv.Name); for (int groupIdx = 0; groupIdx < gmv.NbGroups; groupIdx++) { WriteReserveGroup(S, cgd, FT, typeName, groupIdx, gmv.Group(groupIdx).Length); } } }
public static void GenerateGroupSizeArray(Specification S, G25.CG.Shared.CGdata cgd, StringBuilder SB) { // group size G25.GMV gmv = S.m_GMV; SB.AppendLine("const int " + S.m_namespace + "_groupSize[" + gmv.NbGroups + "] = {"); SB.Append("\t"); for (int i = 0; i < gmv.NbGroups; i++) { if (i > 0) { SB.Append(", "); } SB.Append(gmv.Group(i).Length); } SB.AppendLine(""); SB.AppendLine("};"); }
private static string GetDualCodeCppOrC(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.Metric M, G25.CG.Shared.FuncArgInfo[] FAI, string resultName, bool dual) { G25.GMV gmv = S.m_GMV; StringBuilder SB = new StringBuilder(); string agu = (S.OutputC()) ? FAI[0].Name + "->gu" : FAI[0].Name + ".gu()"; string ac = (S.OutputC()) ? FAI[0].Name + "->c" : FAI[0].Name + ".getC()"; // allocate memory to store result: SB.AppendLine("int idx = 0;"); bool resultIsScalar = false; bool initResultToZero = true; // must init to zero because of compression SB.Append(GPparts.GetExpandCode(S, cgd, FT, null, resultIsScalar, initResultToZero)); // get number of groups: int nbGroups = gmv.NbGroups; // for each combination of groups, check if the dual goes from one to the other for (int gi = 0; gi < nbGroups; gi++) { SB.AppendLine("if (" + agu + " & " + (1 << gi) + ") {"); for (int go = 0; go < nbGroups; go++) { string funcName = (dual) ? GetDualPartFunctionName(S, FT, M, gi, go) : GetUndualPartFunctionName(S, FT, M, gi, go); Tuple <string, string, string> key = new Tuple <string, string, string>(FT.type, M.m_name, funcName); if (cgd.m_gmvDualPartFuncNames.ContainsKey(key) && cgd.m_gmvDualPartFuncNames[key]) { SB.AppendLine("\t" + funcName + "(" + ac + " + idx, c + " + gmv.GroupStartIdx(go) + ");"); } } if (gi < (nbGroups - 1)) { SB.AppendLine("\tidx += " + gmv.Group(gi).Length + ";"); } SB.AppendLine("}"); SB.AppendLine(""); } // compress result SB.Append(GPparts.GetCompressCode(S, FT, FAI, resultName, resultIsScalar)); return(SB.ToString()); } // end of GetDualCodeCppOrC()
public static void GenerateGroupSizeArray(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd) { // group size string accessModifierArr = Keywords.ConstArrayAccessModifier(S); G25.GMV gmv = S.m_GMV; new G25.CG.Shared.Comment("This array can be used to lookup the number of coordinates for a group part of a general multivector.").Write(SB, S, 1); SB.Append("\tpublic " + accessModifierArr + " int[] GroupSize = { "); for (int i = 0; i < gmv.NbGroups; i++) { if (i > 0) { SB.Append(", "); } SB.Append(gmv.Group(i).Length); } SB.AppendLine(" };"); }
/// <summary> /// Writes functions to copy GMVs from one float type to another. /// </summary> /// <param name="SB">Where the output goes.</param> /// <param name="S"></param> /// <param name="cgd">Results go here. Also intermediate data for code generation. Also contains plugins and cog.</param> /// <param name="dstFT"></param> public static void WriteGMVtoGMVcopy(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd, FloatType dstFT) { G25.GMV gmv = S.m_GMV; foreach (G25.FloatType srcFT in S.m_floatTypes) { string srcClassName = srcFT.GetMangledName(S, gmv.Name); //string dstClassName = dstFT.GetMangledName(S, gmv.Name); string funcName = GetSetFuncName(S); string funcDecl = "\tpublic void " + funcName + "(" + srcClassName + " src)"; int nbTabs = 1; new G25.CG.Shared.Comment("sets this to multivector value.").Write(SB, S, nbTabs); SB.Append(funcDecl); SB.AppendLine(" {"); SB.AppendLine("\t\t" + GetAllocateGroupsString(S) + "(src.gu());"); for (int g = 0; g < gmv.NbGroups; g++) { SB.AppendLine("\t\tif (m_c[" + g + "] != null) {"); if (dstFT == srcFT) { SB.Append("\t\t\t" + G25.CG.Shared.Util.GetCopyCode(S, dstFT, "src.m_c[" + g + "]", "m_c[" + g + "]", gmv.Group(g).Length)); } else { SB.AppendLine("\t\t\tfor (int i = 0; i < " + gmv.Group(g).Length + "; i++)"); SB.AppendLine("\t\t\t\tm_c[" + g + "][i] = (" + dstFT.type + ")src.m_c[" + g + "][i];"); } SB.AppendLine("\t\t}"); } if (S.m_reportUsage) { SB.AppendLine("\t\tm_t = src.m_t;"); } SB.AppendLine("\t}"); } }
/// <summary> /// Writes functions to extract coordinates from the GMV /// </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 WriteCoordAccess(Specification S, G25.CG.Shared.CGdata cgd) { //StringBuilder declSB = cgd.m_declSB; //StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; G25.GMV gmv = S.m_GMV; foreach (G25.FloatType FT in S.m_floatTypes) { string typeName = FT.GetMangledName(S, gmv.Name); for (int groupIdx = 0; groupIdx < gmv.NbGroups; groupIdx++) { for (int elementIdx = 0; elementIdx < gmv.Group(groupIdx).Length; elementIdx++) { WriteCoordExtractFunction(S, cgd, FT, typeName, groupIdx, elementIdx, gmv.Group(groupIdx)[elementIdx]); WriteCoordSetFunction(S, cgd, FT, typeName, groupIdx, elementIdx, gmv.Group(groupIdx).Length, gmv.Group(groupIdx)[elementIdx]); } } } }
} // end of GetDualCodeCppOrC() private static string GetDualCodeCSharpOrJava(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.Metric M, G25.CG.Shared.FuncArgInfo[] FAI, string resultName, bool dual) { G25.GMV gmv = S.m_GMV; StringBuilder SB = new StringBuilder(); bool resultIsScalar = false; bool initResultToZero = true; // must init to zero because of compression SB.Append(GPparts.GetExpandCode(S, cgd, FT, FAI, resultIsScalar, initResultToZero)); // get number of groups: int nbGroups = gmv.NbGroups; // for each combination of groups, check if the dual goes from one to the other for (int gi = 0; gi < nbGroups; gi++) { SB.AppendLine("if (ac[" + gi + "] != null) {"); for (int go = 0; go < nbGroups; go++) { string funcName = (dual) ? GetDualPartFunctionName(S, FT, M, gi, go) : GetUndualPartFunctionName(S, FT, M, gi, go); Tuple <string, string, string> key = new Tuple <string, string, string>(FT.type, M.m_name, funcName); if (cgd.m_gmvDualPartFuncNames.ContainsKey(key) && cgd.m_gmvDualPartFuncNames[key]) { SB.AppendLine("\tif (cc[" + go + "] == null) cc[" + go + "] = new " + FT.type + "[" + gmv.Group(go).Length + "];"); SB.AppendLine("\t" + funcName + "(ac[" + gi + "], cc[" + go + "]);"); } } SB.AppendLine("}"); SB.AppendLine(""); } SB.AppendLine("return new " + FT.GetMangledName(S, gmv.Name) + "(cc);"); return(SB.ToString()); } // end of GetDualCodeCppOrC()
/// <summary> /// Generates functions which compute the dual or undual of general multivectors, on a group by group basis. /// /// This function should be called early on in the code generation process, at least /// before any of the <c>GetDualCode()</c> functions is called. /// </summary> /// <param name="S">Specification (used for output language, GMV).</param> /// <param name="cgd">Where the result goes.</param> public static void WriteDualParts(Specification S, CGdata cgd) { G25.GMV gmv = S.m_GMV; string name1 = "A"; string name2 = "B"; string name3 = "C"; bool ptr = true; int allGroups = -1; bool mustCast = false; int nbBaseTabs = (S.OutputCSharpOrJava()) ? 1 : 0; int nbCodeTabs = nbBaseTabs + 1; bool writeZeros = false; // get symbolic multivectors RefGA.Multivector[] M1 = null; if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) { M1 = G25.CG.Shared.Symbolic.GMVtoSymbolicMultivector(S, gmv, name1, ptr, allGroups); } foreach (G25.FloatType FT in S.m_floatTypes) { // map from code fragment to name of function Dictionary <string, string> generatedCode = new Dictionary <string, string>(); foreach (G25.Metric M in S.m_metric) { if (M.m_metric.IsDegenerate()) { continue; // do not generate code for degenerate metrics } for (int g1 = 0; g1 < gmv.NbGroups; g1++) { for (int d = 1; d >= 0; d--) // d = 1 -> generate dual, d = 0 -> generate undual { // get value of operation, name of function: RefGA.Multivector value = null; if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) { try { value = (d == 0) ? RefGA.Multivector.Undual(M1[g1], M.m_metric) : RefGA.Multivector.Dual(M1[g1], M.m_metric); } catch (Exception) { cgd.AddError(new G25.UserException("Non-invertable pseudoscalar. Do not generate (un)dual functions for degenerate metrics.")); return; } if (M.m_round) { value = value.Round(1e-14); } } int grade = gmv.Group(g1)[0].Grade(); int dualGrade = S.m_dimension - grade; for (int g3 = 0; g3 < gmv.NbGroups; g3++) { if (gmv.Group(g3)[0].Grade() == dualGrade) { string funcName = (d == 0) ? GetUndualPartFunctionName(S, FT, M, g1, g3) : GetDualPartFunctionName(S, FT, M, g1, g3); // get assignment code string code = ""; if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) { // full code expansion int dstBaseIdx = 0; code = G25.CG.Shared.CodeUtil.GenerateGMVassignmentCode(S, FT, mustCast, gmv, name3, g3, dstBaseIdx, value, nbCodeTabs, writeZeros); } else if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) { // runtime code code = GetRuntimeDualCode(S, FT, M, d, g1, g3, name1, name2, name3); } cgd.m_gmvDualPartFuncNames[new Tuple <string, string, string>(FT.type, M.m_name, funcName)] = (code.Length > 0); if (code.Length == 0) { continue; // only if code is non-empty } // is the following ever required: (i.e. the dual of a basis blade wrt to the full space is not a single basis blade?) //if (!M.m_metric.IsDiagonal()) // code = code.Replace("=", "+="); // check if code was already generated, and, if so, reuse it if (generatedCode.ContainsKey(code)) { // ready generated: call that function code = new string('\t', nbCodeTabs) + generatedCode[code] + "(" + name1 + ", " + name3 + ");\n"; } else { // not generated yet: remember code -> function generatedCode[code] = funcName; } // write comment string comment = "Computes the partial " + ((d == 0) ? "un" : "") + "dual (w.r.t. full space) of a multivector."; string ACCESS = ""; if (S.OutputJava()) { ACCESS = "protected final static "; } else if (S.OutputCSharp()) { ACCESS = "protected internal static "; } string ARR = (S.OutputCSharpOrJava()) ? "[] " : " *"; string CONST = (S.OutputCSharpOrJava()) ? "" : "const "; string funcDecl = ACCESS + "void " + funcName + "(" + CONST + FT.type + ARR + name1 + ", " + FT.type + ARR + name3 + ")"; if (S.OutputCppOrC()) { new Comment(comment).Write(cgd.m_declSB, S, nbBaseTabs); cgd.m_declSB.Append(funcDecl); cgd.m_declSB.AppendLine(";"); } else { new Comment(comment).Write(cgd.m_defSB, S, nbBaseTabs); } // emit def cgd.m_defSB.Append('\t', nbBaseTabs); cgd.m_defSB.Append(funcDecl); cgd.m_defSB.AppendLine(" {"); cgd.m_defSB.Append(code); cgd.m_defSB.Append('\t', nbBaseTabs); cgd.m_defSB.AppendLine("}"); } } // end of loop over all output groups } // end of loop over undual (0) and dual(1) } // end of loop over all input groups } // end of loop over all metric } // end of loop over all float types } // end of function WriteDualParts()
public static void GenerateBasisElementArrays(Specification S, G25.CG.Shared.CGdata cgd, StringBuilder SB) { G25.GMV gmv = S.m_GMV; double[] s = new double[1 << S.m_dimension]; int[] IndexByBitmap = new int[1 << S.m_dimension]; int[] BitmapByIndex = new int[1 << S.m_dimension]; int[] GradeByBitmap = new int[1 << S.m_dimension]; int[] GroupByBitmap = new int[1 << S.m_dimension]; SB.AppendLine("const double " + S.m_namespace + "_basisElementSignByIndex[" + (1 << S.m_dimension) + "] ="); SB.Append("\t{"); { bool comma = false; int idx = 0; for (int i = 0; i < gmv.NbGroups; i++) { for (int j = 0; j < gmv.Group(i).Length; j++) { if (comma) { SB.Append(", "); } RefGA.BasisBlade B = gmv.Group(i)[j]; s[gmv.Group(i)[j].bitmap] = B.scale; IndexByBitmap[B.bitmap] = idx; BitmapByIndex[idx] = (int)B.bitmap; GradeByBitmap[B.bitmap] = B.Grade(); GroupByBitmap[B.bitmap] = i; SB.Append(B.scale); comma = true; idx++; } } } SB.AppendLine("};"); SB.AppendLine("const double " + S.m_namespace + "_basisElementSignByBitmap[" + (1 << S.m_dimension) + "] ="); SB.Append("\t{"); { for (int i = 0; i < s.Length; i++) { if (i > 0) { SB.Append(", "); } SB.Append(s[i]); } } SB.AppendLine("};"); SB.AppendLine("const int " + S.m_namespace + "_basisElementIndexByBitmap[" + (1 << S.m_dimension) + "] ="); SB.Append("\t{"); { for (int i = 0; i < s.Length; i++) { if (i > 0) { SB.Append(", "); } SB.Append(IndexByBitmap[i]); } } SB.AppendLine("};"); SB.AppendLine("const int " + S.m_namespace + "_basisElementBitmapByIndex[" + (1 << S.m_dimension) + "] ="); SB.Append("\t{"); { for (int i = 0; i < s.Length; i++) { if (i > 0) { SB.Append(", "); } SB.Append(BitmapByIndex[i]); } } SB.AppendLine("};"); SB.AppendLine("const int " + S.m_namespace + "_basisElementGradeByBitmap[" + (1 << S.m_dimension) + "] ="); SB.Append("\t{"); { for (int i = 0; i < s.Length; i++) { if (i > 0) { SB.Append(", "); } SB.Append(GradeByBitmap[i]); } } SB.AppendLine("};"); SB.AppendLine("const int " + S.m_namespace + "_basisElementGroupByBitmap[" + (1 << S.m_dimension) + "] ="); SB.Append("\t{"); { for (int i = 0; i < s.Length; i++) { if (i > 0) { SB.Append(", "); } SB.Append(GroupByBitmap[i]); } } SB.AppendLine("};"); } // end of GenerateBasisElementArrays()
} // end of GetApplyGomCodeCppOrC private static string GetApplyGomCodeCSharpOrJava(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.CG.Shared.FuncArgInfo[] FAI, string resultName) { G25.GMV gmv = S.m_GMV; bool groupedByGrade = gmv.IsGroupedByGrade(S.m_dimension); StringBuilder SB = new StringBuilder(); // allocate memory to store result: SB.AppendLine(FT.type + "[][] bc = " + FAI[1].Name + ".to_" + FAI[1].MangledTypeName + "().c();"); bool resultIsScalar = false; bool initResultToZero = !groupedByGrade; SB.Append(GPparts.GetExpandCode(S, cgd, FT, null, resultIsScalar, initResultToZero)); // get number of groups: int nbGroups = gmv.NbGroups; // for each combination of groups, check if the OM goes from one to the other for (int srcGroup = 0; srcGroup < nbGroups; srcGroup++) { SB.AppendLine("if (bc[" + srcGroup + "] != null) {"); for (int dstGroup = 0; dstGroup < nbGroups; dstGroup++) { string funcName = GetGomPartFunctionName(S, FT, srcGroup, dstGroup); Tuple <string, string> key = new Tuple <string, string>(FT.type, funcName); if (cgd.m_gmvGomPartFuncNames.ContainsKey(key) && cgd.m_gmvGomPartFuncNames[key]) { string allocCcode = "if (cc[" + dstGroup + "] == null) cc[" + dstGroup + "] = new " + FT.type + "[" + gmv.Group(dstGroup).Length + "];"; SB.AppendLine("\t" + allocCcode); SB.AppendLine("\t" + funcName + "(" + FAI[0].Name + ", bc[" + srcGroup + "], cc[" + dstGroup + "]);"); } } SB.AppendLine("}"); SB.AppendLine(""); } SB.AppendLine("return new " + FT.GetMangledName(S, gmv.Name) + "(cc);"); return(SB.ToString()); } // end of GetApplyGomCodeCSharpOrJava()
public static void GenerateBasisElementArrays(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd) { string accessModifierArr = Keywords.ConstArrayAccessModifier(S); G25.GMV gmv = S.m_GMV; double[] s = new double[1 << S.m_dimension]; int[] IndexByBitmap = new int[1 << S.m_dimension]; int[] BitmapByIndex = new int[1 << S.m_dimension]; int[] GradeByBitmap = new int[1 << S.m_dimension]; int[] GroupByBitmap = new int[1 << S.m_dimension]; new G25.CG.Shared.Comment("This array of integers contains the 'sign' (even/odd permutation of canonical order) of basis elements in the general multivector.\n" + "Use it to answer 'what is the permutation of the coordinate at index [x]'?").Write(SB, S, 1); SB.AppendLine("\tpublic " + accessModifierArr + " double[] BasisElementSignByIndex = new double[]"); SB.Append("\t\t{"); { bool comma = false; int idx = 0; for (int i = 0; i < gmv.NbGroups; i++) { for (int j = 0; j < gmv.Group(i).Length; j++) { if (comma) { SB.Append(", "); } RefGA.BasisBlade B = gmv.Group(i)[j]; s[gmv.Group(i)[j].bitmap] = B.scale; IndexByBitmap[B.bitmap] = idx; BitmapByIndex[idx] = (int)B.bitmap; GradeByBitmap[B.bitmap] = B.Grade(); GroupByBitmap[B.bitmap] = i; SB.Append(B.scale); comma = true; idx++; } } } SB.AppendLine("};"); new G25.CG.Shared.Comment("This array of integers contains the 'sign' (even/odd permutation of canonical order) of basis elements in the general multivector.\n" + "Use it to answer 'what is the permutation of the coordinate of bitmap [x]'?").Write(SB, S, 1); SB.AppendLine("\tpublic " + accessModifierArr + " double[] BasisElementSignByBitmap = new double[]"); SB.Append("\t\t{"); { for (int i = 0; i < s.Length; i++) { if (i > 0) { SB.Append(", "); } SB.Append(s[i]); } } SB.AppendLine("};"); new G25.CG.Shared.Comment("This array of integers contains the order of basis elements in the general multivector.\n" + "Use it to answer: 'at what index do I find basis element [x] (x = basis vector bitmap)?'").Write(SB, S, 1); SB.AppendLine("\tpublic " + accessModifierArr + " int[] BasisElementIndexByBitmap = new int[]"); SB.Append("\t\t{"); { for (int i = 0; i < s.Length; i++) { if (i > 0) { SB.Append(", "); } SB.Append(IndexByBitmap[i]); } } SB.AppendLine("};"); new G25.CG.Shared.Comment("This array of integers contains the indices of basis elements in the general multivector.\n" + "Use it to answer: 'what basis element do I find at index [x]'?").Write(SB, S, 1); SB.AppendLine("\tpublic " + accessModifierArr + " int[] BasisElementBitmapByIndex = new int[]"); SB.Append("\t\t{"); { for (int i = 0; i < s.Length; i++) { if (i > 0) { SB.Append(", "); } SB.Append(BitmapByIndex[i]); } } SB.AppendLine("};"); new G25.CG.Shared.Comment("This array of grade of each basis elements in the general multivector.\n" + "Use it to answer: 'what is the grade of basis element bitmap [x]'?").Write(SB, S, 1); SB.AppendLine("\tpublic " + accessModifierArr + " int[] BasisElementGradeByBitmap = new int[]"); SB.Append("\t\t{"); { for (int i = 0; i < s.Length; i++) { if (i > 0) { SB.Append(", "); } SB.Append(GradeByBitmap[i]); } } SB.AppendLine("};"); new G25.CG.Shared.Comment("This array of group of each basis elements in the general multivector.\n" + "Use it to answer: 'what is the group of basis element bitmap [x]'?").Write(SB, S, 1); SB.AppendLine("\tpublic " + accessModifierArr + " int[] BasisElementGroupByBitmap = new int[]"); SB.Append("\t\t{"); { for (int i = 0; i < s.Length; i++) { if (i > 0) { SB.Append(", "); } SB.Append(GroupByBitmap[i]); } } SB.AppendLine("};"); } // end of GenerateBasisElementArrays()
/// <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) { StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; G25.GMV gmv = S.m_GMV; foreach (G25.FloatType FT in S.m_floatTypes) { string srcClassName = FT.GetMangledName(S, gmv.Name); for (int s = 0; s < S.m_SMV.Count; s++) { G25.SMV smv = S.m_SMV[s]; string dstClassName = FT.GetMangledName(S, smv.Name); bool dstPtr = true; String[] smvAccessStr = G25.CG.Shared.CodeUtil.GetAccessStr(S, smv, G25.CG.Shared.SmvUtil.THIS, dstPtr); string funcName = "set"; // do we inline this func? string inlineStr = G25.CG.Shared.Util.GetInlineString(S, S.m_inlineSet, " "); string funcDecl = inlineStr + "void " + dstClassName + "::" + funcName + "(const " + srcClassName + " &src)"; defSB.Append(funcDecl); { defSB.AppendLine(" {"); defSB.AppendLine("\tconst " + FT.type + " *ptr = src.getC();\n"); // get a dictionary which tells you for each basis blade of 'smv' where it is in 'gmv' 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) { if (KVP.Value.Value1 == g) { groupIsUsedBySMV = true; break; } } // if group is present in GMV: defSB.AppendLine("\tif (src.gu() & " + (1 << g) + ") {"); if (groupIsUsedBySMV) { bool mustCast = false; bool srcPtr = true; int nbTabs = 2; 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); } if ((g + 1) <= highestGroup) { defSB.AppendLine("\t\tptr += " + gmv.Group(g).Length + ";"); } defSB.AppendLine("\t}"); // else, if group is not present in GMV: if (groupIsUsedBySMV) { defSB.AppendLine("\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" + smvAccessStr[bladeIdx] + " = " + FT.DoubleToString(S, 0.0) + ";"); } } defSB.AppendLine("\t}"); } } defSB.AppendLine("}"); } } // end of loop over all SMVs } // end of loop over all float types } // end of WriteGMVtoSMVcopy()
/// <summary> /// Writes the definition of an GMV struct to 'SB' (including comments). /// </summary> /// <param name="SB">Where the code goes.</param> /// <param name="S">Used for basis vector names and output language.</param> /// <param name="cgd">Intermediate data for code generation. Also contains plugins and cog.</param> /// <param name="FT">Float point type of 'SMV'.</param> /// <param name="gmv">The general multivector for which the struct should be written.</param> public static void WriteGMVstruct(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd, FloatType FT, G25.GMV gmv) { SB.AppendLine(""); { // comments for type: SB.AppendLine("/**"); SB.AppendLine(" * This struct can hold a general multivector."); SB.AppendLine(" * "); SB.AppendLine(" * The coordinates are stored in type " + FT.type + "."); SB.AppendLine(" * "); SB.AppendLine(" * There are " + gmv.NbGroups + " coordinate groups:"); for (int g = 0; g < gmv.NbGroups; g++) { SB.Append(" * group " + g + ":"); for (int i = 0; i < gmv.Group(g).Length; i++) { if (i > 0) { SB.Append(", "); } SB.Append(gmv.Group(g)[i].ToString(S.m_basisVectorNames)); } if (gmv.Group(g).Length > 0) { SB.Append(" (grade " + gmv.Group(g)[0].Grade() + ")"); } SB.AppendLine("."); } SB.AppendLine(" * "); switch (S.m_GMV.MemoryAllocationMethod) { case G25.GMV.MEM_ALLOC_METHOD.PARITY_PURE: SB.AppendLine(" * " + (gmv.NbCoordinates / 2) + " " + FT.type + "s are allocated inside the struct ('parity pure')."); SB.AppendLine(" * Hence creating a multivector which needs more than that number of coordinates "); SB.AppendLine(" * will result in unpredictable behaviour (buffer overflow)."); break; case G25.GMV.MEM_ALLOC_METHOD.FULL: SB.AppendLine(" * " + gmv.NbCoordinates + " " + FT.type + "s are allocated inside the struct."); break; } SB.AppendLine(" */"); } // end of comment // typedef SB.AppendLine("typedef struct "); SB.AppendLine("{"); // group/grade usage SB.AppendLine("\t/** group/grade usage (a bitmap which specifies which groups/grades are stored in 'c', below). */"); SB.AppendLine("\tint gu;"); // coordinates switch (S.m_GMV.MemoryAllocationMethod) { // case G25.GMV.MEM_ALLOC_METHOD.DYNAMIC: // SB.AppendLine("\t" + FT.type + " *c; ///< the coordinates (array is allocated using realloc())"); // break; case G25.GMV.MEM_ALLOC_METHOD.PARITY_PURE: SB.AppendLine("\t/** The coordinates (note: parity pure). */"); SB.AppendLine("\t" + FT.type + " c[" + (gmv.NbCoordinates / 2) + "];"); break; case G25.GMV.MEM_ALLOC_METHOD.FULL: SB.AppendLine("\t/** The coordinates (full). */"); SB.AppendLine("\t" + FT.type + " c[" + (gmv.NbCoordinates) + "];"); break; } // If we report non-optimized function usage, we need to know original type of GMVs: if (S.m_reportUsage) { SB.AppendLine("\t/** Specialized multivector type. Used to report about non-optimized function usage. */"); SB.AppendLine("\tint t;"); } SB.AppendLine("} " + FT.GetMangledName(S, gmv.Name) + ";"); }
} // end of WriteGMVtoSMVcopy() /// <summary> /// Writes functions to copy SMVs to GMVs /// </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 WriteSMVtoGMVcopy(Specification S, G25.CG.Shared.CGdata cgd) { StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; G25.GMV gmv = S.m_GMV; Boolean gmvParityPure = (S.m_GMV.MemoryAllocationMethod == G25.GMV.MEM_ALLOC_METHOD.PARITY_PURE); foreach (G25.FloatType FT in S.m_floatTypes) { String dstClassName = FT.GetMangledName(S, gmv.Name); for (int s = 0; s < S.m_SMV.Count; s++) { G25.SMV smv = S.m_SMV[s]; // do not generate converter if the GMV cannot hold the type if (gmvParityPure && (!smv.IsParityPure())) { continue; } string srcClassName = FT.GetMangledName(S, smv.Name); string funcName = "set"; // do we inline this func? string inlineStr = G25.CG.Shared.Util.GetInlineString(S, S.m_inlineSet, " "); string funcDecl = inlineStr + "void " + dstClassName + "::" + funcName + "(const " + srcClassName + " &src)"; defSB.Append(funcDecl); { defSB.AppendLine(" {"); // get a dictionary which tells you for each basis blade of 'gmv' where it is in 'smv' Dictionary <Tuple <int, int>, Tuple <int, int> > D = G25.MV.GetCoordMap(smv, gmv); // convert SMV to symbolic Multivector: bool smvPtr = false; RefGA.Multivector value = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(S, smv, "src", smvPtr); // find out which groups are present int gu = 0; foreach (KeyValuePair <Tuple <int, int>, Tuple <int, int> > KVP in D) { gu |= 1 << KVP.Value.Value1; } // generate the code to set group usage: defSB.AppendLine("\t" + SET_GROUP_USAGE + "(" + gu + ");"); // a helper pointer which is incremented string dstArrName = "ptr"; defSB.AppendLine("\t" + FT.type + " *" + dstArrName + " = m_c;"); // for each used group, generate the assignment code for (int g = 0; (1 << g) <= gu; g++) { if (((1 << g) & gu) != 0) { bool mustCast = false; int nbTabs = 1; bool writeZeros = true; String str = G25.CG.Shared.CodeUtil.GenerateGMVassignmentCode(S, FT, mustCast, gmv, dstArrName, g, value, nbTabs, writeZeros); defSB.Append(str); if ((1 << (g + 1)) <= gu) { defSB.AppendLine("\tptr += " + gmv.Group(g).Length + ";"); } } } if (S.m_reportUsage) { defSB.AppendLine("\tm_t = " + G25.CG.Shared.ReportUsage.GetSpecializedConstantName(S, smv.Name) + ";"); } defSB.AppendLine("}"); } } // end of loop over all SMVs } // end of loop over all float types } // end of WriteGMVtoSMVcopy()
private static string GetApplyGomCodeCppOrC(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.CG.Shared.FuncArgInfo[] FAI, string resultName) { G25.GMV gmv = S.m_GMV; bool groupedByGrade = gmv.IsGroupedByGrade(S.m_dimension); StringBuilder SB = new StringBuilder(); // allocate memory to store result: SB.AppendLine("int idxB = 0, gu = 0, idxC = 0;"); bool resultIsScalar = false; bool initResultToZero = !groupedByGrade; SB.Append(GPparts.GetExpandCode(S, cgd, FT, null, resultIsScalar, initResultToZero)); string bgu = (S.OutputC()) ? FAI[1].Name + "->gu" : FAI[1].Name + ".gu()"; string bc = (S.OutputC()) ? FAI[1].Name + "->c" : FAI[1].Name + ".getC()"; // get number of groups: int nbGroups = gmv.NbGroups; int dstGrade = 0; int srcGradeSizeAccumulator = 0; // for each combination of groups, check if the OM goes from one to the other for (int srcGroup = 0; srcGroup < nbGroups; srcGroup++) { // increment the index into 'C' when we switch grade int srcGrade = gmv.Group(srcGroup)[0].Grade(); if (srcGrade != dstGrade) { if (!groupedByGrade) { SB.AppendLine("idxC += " + srcGradeSizeAccumulator + ";"); SB.AppendLine(""); } dstGrade = srcGrade; srcGradeSizeAccumulator = 0; } srcGradeSizeAccumulator += gmv.Group(srcGroup).Length; SB.AppendLine("if (" + bgu + " & " + (1 << srcGroup) + ") {"); int dstGradeSizeAccumulator = 0; for (int dstGroup = 0; dstGroup < nbGroups; dstGroup++) { string funcName = GetGomPartFunctionName(S, FT, srcGroup, dstGroup); Tuple <string, string> key = new Tuple <string, string>(FT.type, funcName); if (cgd.m_gmvGomPartFuncNames.ContainsKey(key) && cgd.m_gmvGomPartFuncNames[key]) { SB.AppendLine("\t" + funcName + "(" + FAI[0].Name + ", " + bc + " + idxB, c + idxC + " + dstGradeSizeAccumulator + ");"); } if (gmv.Group(dstGroup)[0].Grade() == srcGrade) { dstGradeSizeAccumulator += gmv.Group(dstGroup).Length; } } if (srcGroup < (nbGroups - 1)) { SB.AppendLine("\tidxB += " + gmv.Group(srcGroup).Length + ";"); if (groupedByGrade) { SB.AppendLine("\tidxC += " + gmv.Group(srcGroup).Length + ";"); SB.AppendLine(""); } } SB.AppendLine("}"); SB.AppendLine(""); } // generate code to compress result string cgu = (groupedByGrade) ? bgu : null; // null means: all groups/grades are present SB.Append(GPparts.GetCompressCode(S, FT, FAI, resultName, resultIsScalar, cgu)); // todo: bgu should be 63 when not grouped by grade return(SB.ToString()); } // end of GetApplyGomCodeCppOrC