/// <summary> /// Resolves a converter (underscore constructor) dependency. /// Searches for a converter from 'fromType' to 'toType'. /// /// If the function is not found, this is also enlisted in cgd.m_missingDependencies. /// Call cgd.PrintMissingDependencies() should be called to report the missing dependencies /// to the end-user. /// </summary> /// <param name="S">The spec.</param> /// <param name="cgd">Missing dependencies go into cgd.m_missingDependencies.</param> /// <param name="fromType"></param> /// <param name="toType"></param> /// <param name="FT"></param> /// <returns></returns> public static string GetConverterDependency(Specification S, CGdata cgd, string fromType, string toType, G25.FloatType FT) { // look for 'funcName' in all G25.fgs in the spec // string funcName = "_" + FT.GetMangledName(S, toType); string funcName = "_" + toType; foreach (G25.fgs F in S.m_functions) { if (F.IsConverter(S)) // is 'F' a converter (underscore constructor)? { if ((F.Name == funcName) && (F.ArgumentTypeNames[0] == fromType)) { return G25.CG.Shared.Converter.GetConverterName(S, F, FT.GetMangledName(S, fromType), FT.GetMangledName(S, toType)); } } } // converter not found: add it to missing deps: { // add dependency to list of missing deps: string outputName = null; string[] argumentTypes = new string[] { fromType }; string[] argVarNames = null; string returnTypeName = null; string metricName = null; string comment = null; Dictionary<string, string> options = null; G25.fgs F = new G25.fgs(funcName, outputName, returnTypeName, argumentTypes, argVarNames, new string[] { FT.type }, metricName, comment, options); cgd.AddMissingDependency(S, F); } // return fictional name: G25.fgs tmpF = null; return "missingFunction_" + G25.CG.Shared.Converter.GetConverterName(S, tmpF, FT.GetMangledName(S, fromType), FT.GetMangledName(S, toType)); }
/// <summary> /// Returns the name of a generated function (for example <c>gp_mv_mv</c>). /// The function is found by looking through all G25.FGS in the Specification. /// /// If the function is not found, a fictional name is returned, i.e. "missingFunction_" + functionName. /// This name will then show up in the generated code, which will not compile as a result. /// /// If the function is not found, this is also enlisted in cgd.m_missingDependencies. /// Call cgd.PrintMissingDependencies() should be called to report the missing dependencies /// to the end-user. /// </summary> /// <param name="S">The spec.</param> /// <param name="cgd">Missing dependencies go into cgd.m_missingDependencies.</param> /// <param name="functionName">Basic name of the function to be found.</param> /// <param name="argumentTypes">Names of the arguments types (not mangled).</param> /// <param name="returnTypeName">Name of the return type (can be null or "" for default return type).</param> /// <param name="FT">Floating point type.</param> /// <param name="metricName">(optional, can be null for don't care)</param> /// <returns>The mangled name of the function.</returns> public static string GetDependency(Specification S, CGdata cgd, string functionName, string[] argumentTypes, string returnTypeName, G25.FloatType FT, string metricName) { // bool returnTrueName = dependent on cgd.mode try { return(GetFunctionName(S, functionName, argumentTypes, returnTypeName, FT, metricName)); } catch (DependencyException) { // function not found, return a fictional name, and remember dependency G25.fgs F = null; { // get name of dep, and make sure it does not get mangled string outputName = functionName + cgd.GetDontMangleUniqueId(); if (returnTypeName != null) { outputName = outputName + "_returns_" + returnTypeName; } // add dependency to list of missing deps: string[] argVarNames = null; Dictionary <String, String> options = null; string comment = null; G25.fgs tmpF = new G25.fgs(functionName, outputName, returnTypeName, argumentTypes, argVarNames, new String[] { FT.type }, metricName, comment, options); F = cgd.AddMissingDependency(S, tmpF); } return(cgd.m_dependencyPrefix + F.OutputName); } } // end of GetDependency()
public static G25.VariableType CreateSyntheticSMVtype(Specification S, CGdata cgd, FloatType FT, RefGA.Multivector value) { // make up list of basis blades rsbbp.BasisBlade[] L = new rsbbp.BasisBlade[value.BasisBlades.Length]; for (int i = 0 ; i < value.BasisBlades.Length; i++) { RefGA.BasisBlade B = value.BasisBlades[i]; if (B.symScale == null) L[i] = new rsbbp.BasisBlade(new RefGA.BasisBlade(B.bitmap), B.scale); // constant value else L[i] = new rsbbp.BasisBlade(new RefGA.BasisBlade(B.bitmap)); // non-const value } // get other required info String name = "nameOfType"; SMV.MULTIVECTOR_TYPE mvType = SMV.MULTIVECTOR_TYPE.MULTIVECTOR; String comment = "MISSING; PLEASE ADD TO SPECIFICATION"; //String constantName = null; // create the type G25.SMV synSMV = new G25.SMV(name, L, mvType, comment); // throw exception throw new G25.UserException("Missing specialized multivector type.\n" + "Please add the following XML to the specification to fix the dependency:\n" + XML.SMVtoXmlString(S, synSMV)); }
public static G25.VariableType CreateSyntheticSMVtype(Specification S, CGdata cgd, FloatType FT, RefGA.Multivector value) { // make up list of basis blades rsbbp.BasisBlade[] L = new rsbbp.BasisBlade[value.BasisBlades.Length]; for (int i = 0; i < value.BasisBlades.Length; i++) { RefGA.BasisBlade B = value.BasisBlades[i]; if (B.symScale == null) { L[i] = new rsbbp.BasisBlade(new RefGA.BasisBlade(B.bitmap), B.scale); // constant value } else { L[i] = new rsbbp.BasisBlade(new RefGA.BasisBlade(B.bitmap)); // non-const value } } // get other required info String name = "nameOfType"; SMV.MULTIVECTOR_TYPE mvType = SMV.MULTIVECTOR_TYPE.MULTIVECTOR; String comment = "MISSING; PLEASE ADD TO SPECIFICATION"; //String constantName = null; // create the type G25.SMV synSMV = new G25.SMV(name, L, mvType, comment); // throw exception throw new G25.UserException("Missing specialized multivector type.\n" + "Please add the following XML to the specification to fix the dependency:\n" + XML.SMVtoXmlString(S, synSMV)); }
/// <summary> /// Returns the SMV type that can hold an image of a basis vector. /// </summary> public static G25.SMV GetRangeVectorType(Specification S, G25.FloatType FT, CGdata cgd, G25.SOM som) { RefGA.Multivector rangeVectorValue = new RefGA.Multivector(som.RangeVectors); G25.SMV rangeVectorType = (G25.SMV)G25.CG.Shared.SpecializedReturnType.FindTightestMatch(S, rangeVectorValue, FT); if (rangeVectorType == null) // type is missing, add it and tell user to add it to XML { rangeVectorType = (G25.SMV)G25.CG.Shared.SpecializedReturnType.CreateSyntheticSMVtype(S, cgd, FT, rangeVectorValue); } return(rangeVectorType); }
/// <summary> /// Merges all errors from cgd into this CGdata. /// </summary> /// <param name="cgd"></param> public void MergeErrors(CGdata cgd) { lock (m_errors) { if (m_errors != cgd.m_errors) { m_errors.AddRange(cgd.m_errors); } } }
/// <returns>A unique name for the testing function of 'funcName'.</returns> public static string GetTestingFunctionName(Specification S, CGdata cgd, string funcName) { if (S.OutputC()) { return("test_" + funcName); } else { return("test_" + funcName + cgd.GetDontMangleUniqueId()); } }
/// <summary> /// Copy constructor /// </summary> /// <param name="cgd"></param> public CGdata(CGdata cgd) { // copy all from cgd m_plugins = cgd.m_plugins; m_cog = cgd.m_cog; m_gmvGPpartFuncNames = cgd.m_gmvGPpartFuncNames; m_gmvDualPartFuncNames = cgd.m_gmvDualPartFuncNames; m_gmvGomPartFuncNames = cgd.m_gmvGomPartFuncNames; m_missingDependencies = cgd.m_missingDependencies; m_errors = cgd.m_errors; m_feedback = cgd.m_feedback; m_dependencyId = cgd.m_dependencyId; m_dependencyPrefix = cgd.m_dependencyPrefix; }
} // end of function FindTightestMatch() /// <summary> /// The user may have requested a return type (F.ReturnTypeName). /// In that case, the type with the same name is found, or an exception /// is thrown if it does not exists. /// /// Otherwise, finds the (tightest, best) return type for a function 'F' which /// returning the (symbolic) value 'value'. /// This may or may not result in an SMV being found. If no /// type is found and the return type is a scalar, then a floating /// point type may be returned. /// /// If no SMV type is found, then a new type is created, and an exception /// is thrown which described the missing type. /// </summary> /// <param name="S">The specification (used to find SMVs)</param> /// <param name="cgd">Not used currently.</param> /// <param name="F">Function description (used for user-specified return type).</param> /// <param name="FT">Floating point type used in function.</param> /// <param name="value">The symbolic return value.</param> /// <returns>The SMV, FloatType or null if none found.</returns> public static G25.VariableType GetReturnType(Specification S, CGdata cgd, G25.fgs F, FloatType FT, RefGA.Multivector value) { if ((F.ReturnTypeName != null) && (F.ReturnTypeName.Length > 0)) { // The user specified a return type G25.SMV returnSmv = S.GetSMV(F.ReturnTypeName); // is it a SMV? if (returnSmv != null) { return(returnSmv); } G25.FloatType returnFT = S.GetFloatType(F.ReturnTypeName); // is it a specific float? if (returnFT != null) { return(FT); //returnFT; } else if (F.ReturnTypeName == G25.XML.XML_SCALAR) // is it a unspecified float? { return(FT); } // type does not exist: abort (TODO: error message) else { throw new G25.UserException("Non-existant user-specified return type: " + F.ReturnTypeName, XML.FunctionToXmlString(S, F)); // non-existant return type } } else { G25.VariableType RT = FindTightestMatch(S, value, FT); if (RT != null) { return(RT); } else { return(CreateSyntheticSMVtype(S, cgd, FT, value)); } } }
} // end of GetDependency() /// <summary> /// Resolves a converter (underscore constructor) dependency. /// Searches for a converter from 'fromType' to 'toType'. /// /// If the function is not found, this is also enlisted in cgd.m_missingDependencies. /// Call cgd.PrintMissingDependencies() should be called to report the missing dependencies /// to the end-user. /// </summary> /// <param name="S">The spec.</param> /// <param name="cgd">Missing dependencies go into cgd.m_missingDependencies.</param> /// <param name="fromType"></param> /// <param name="toType"></param> /// <param name="FT"></param> /// <returns></returns> public static string GetConverterDependency(Specification S, CGdata cgd, string fromType, string toType, G25.FloatType FT) { // look for 'funcName' in all G25.fgs in the spec // string funcName = "_" + FT.GetMangledName(S, toType); string funcName = "_" + toType; foreach (G25.fgs F in S.m_functions) { if (F.IsConverter(S)) // is 'F' a converter (underscore constructor)? { if ((F.Name == funcName) && (F.ArgumentTypeNames[0] == fromType)) { return(G25.CG.Shared.Converter.GetConverterName(S, F, FT.GetMangledName(S, fromType), FT.GetMangledName(S, toType))); } } } // converter not found: add it to missing deps: { // add dependency to list of missing deps: string outputName = null; string[] argumentTypes = new string[] { fromType }; string[] argVarNames = null; string returnTypeName = null; string metricName = null; string comment = null; Dictionary <string, string> options = null; G25.fgs F = new G25.fgs(funcName, outputName, returnTypeName, argumentTypes, argVarNames, new string[] { FT.type }, metricName, comment, options); cgd.AddMissingDependency(S, F); } // return fictional name: G25.fgs tmpF = null; return("missingFunction_" + G25.CG.Shared.Converter.GetConverterName(S, tmpF, FT.GetMangledName(S, fromType), FT.GetMangledName(S, toType))); }
/// <summary> /// Generates functions which compute parts of the application of a general outermorphism to a general multivector. /// /// This function should be called early on in the code generation process, at least /// before any of the <c>???()</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 WriteGomParts(Specification S, CGdata cgd) { if (S.m_GOM == null) return; // nothing to do if GOM not defiend int nbBaseTabs = (S.OutputCSharpOrJava()) ? 1 : 0; int nbCodeTabs = nbBaseTabs + 1; G25.GMV gmv = S.m_GMV; G25.GOM gom = S.m_GOM; string nameGOM = "O"; string nameSrcGMV = "A"; string nameDstGMV = "C"; // get symbolic multivector value RefGA.Multivector[] M1 = null; { bool ptr = (S.OutputC()); int allGroups = -1; M1 = G25.CG.Shared.Symbolic.GMVtoSymbolicMultivector(S, gmv, nameSrcGMV, 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>(); // loop over all groups of the GMV, multiply with GOM, and assign the result for (int srcGroup = 0; srcGroup < gmv.NbGroups; srcGroup++) { RefGA.Multivector inputValue = M1[srcGroup]; if (inputValue.IsScalar()) continue; // Replace each basis blade in 'inputValue' with its value under the outermorphism. RefGA.Multivector returnValue = RefGA.Multivector.ZERO; // returnValue = gom * gmv[srcGroup] for (int i = 0; i < inputValue.BasisBlades.Length; i++) { // get input blade and domain for that grade RefGA.BasisBlade inputBlade = inputValue.BasisBlades[i]; RefGA.BasisBlade[] domainBlades = gom.DomainForGrade(inputBlade.Grade()); for (int c = 0; c < domainBlades.Length; c++) { // if a match is found in the domain, add range vector to m_returnValue if (domainBlades[c].bitmap == inputBlade.bitmap) { bool ptr = (S.OutputC()); RefGA.Multivector omColumnValue = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(S, gom.DomainSmvForGrade(inputBlade.Grade())[c], nameGOM, ptr); RefGA.Multivector inputBladeScalarMultiplier = new RefGA.Multivector(new RefGA.BasisBlade(inputBlade, 0)); RefGA.Multivector domainBladeScalarMultiplier = new RefGA.Multivector(new RefGA.BasisBlade(domainBlades[c], 0)); returnValue = RefGA.Multivector.Add(returnValue, RefGA.Multivector.gp( RefGA.Multivector.gp(omColumnValue, inputBladeScalarMultiplier), domainBladeScalarMultiplier)); break; // no need to search the other domainBlades too } } } // end of 'compute return value' // assign returnValue to various groups of the gmv for (int dstGroup = 0; dstGroup < gmv.NbGroups; dstGroup++) { bool mustCast = false; bool writeZeros = false; // no need to generate "+= 0.0;" int dstBaseIdx = 0; string code = G25.CG.Shared.CodeUtil.GenerateGMVassignmentCode(S, FT, mustCast, gmv, nameDstGMV, dstGroup, dstBaseIdx, returnValue, nbCodeTabs, writeZeros); string funcName = GetGomPartFunctionName(S, FT, srcGroup, dstGroup); cgd.m_gmvGomPartFuncNames[new Tuple<string, string>(FT.type, funcName)] = (code.Length > 0); if (code.Length == 0) continue; if (!S.m_GMV.IsGroupedByGrade(S.m_dimension)) code = code.Replace("=", "+="); // check if code was already generated, and, if so, reuse it if (generatedCode.ContainsKey(code)) { // ready generated: call that function code = "\t" + generatedCode[code] + "(" + nameGOM + ", " + nameSrcGMV + ", " + nameDstGMV + ");\n"; } else { // not generated yet: remember code -> function generatedCode[code] = funcName; } // write comment string comment = "Computes the partial application of a general outermorphism to a general multivector"; string OM_PTR = ""; if (S.OutputC()) OM_PTR = "*"; else if (S.OutputCpp()) OM_PTR = "&"; string ACCESS = ""; if (S.OutputJava()) ACCESS = "protected 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.GetMangledName(S, gom.Name) + " " + OM_PTR + nameGOM + ", " + CONST + FT.type + ARR + nameSrcGMV + ", " + FT.type + ARR + nameDstGMV + ")"; 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 dest GMV groups } // end of loop over all source GMV groups } // end of loop over all float types }
/// <summary> /// Returns runtime code for check for zero. /// </summary> /// <param name="S">Specification (used for floating points types, output language, GMV).</param> /// <param name="cgd">Output goes here.</param> /// <param name="groupIdx">The group to generate code for.</param> /// <param name="src">Name of source array .</param> /// <param name="epsilon">Name of epsilon variable.</param> protected static string GetRuntimeGmvZeroCode(Specification S, CGdata cgd, int groupIdx, string src, string epsilon) { StringBuilder SB = new StringBuilder(); string TRUE = (S.OutputC()) ? "1" : "true"; string FALSE = (S.OutputC()) ? "0" : "false"; SB.Append("\tint i;\n"); SB.Append("\tfor (i = 0; i < " + (S.m_GMV.Group(groupIdx).Length).ToString() + "; i++)\n"); SB.Append("\t\tif ((" + src + "[i] < -" + epsilon + ") || (" + src + "[i] > " + epsilon + ")) return " + FALSE + ";\n"); SB.Append("\treturn " + TRUE + ";\n"); return SB.ToString(); }
/// <summary> /// Returns code for run-time copying-and-scalar-multiplying/dividing of GMV parts. /// </summary> /// <param name="S">Specification (used for floating points types, output language, GMV).</param> /// <param name="cgd">Output goes here.</param> /// <param name="groupIdx">The group to generate code for.</param> /// <param name="src">Name of source array.</param> /// <param name="dst">Name of destination array.</param> /// <param name="scale">Name of scalar variable.</param> /// <param name="symbol">Symbol to use ("*" or "/").</param> protected static string GetRuntimeGmvCopyMulDivCode(Specification S, CGdata cgd, int groupIdx, string src, string dst, string scale, string symbol) { StringBuilder SB = new StringBuilder(); SB.Append("\tint i;\n"); SB.Append("\tfor (i = 0; i < " + (S.m_GMV.Group(groupIdx).Length).ToString() + "; i++)\n"); SB.Append("\t\t" + dst + "[i] = " + src + "[i] " + symbol + " " + scale + ";\n"); return SB.ToString(); }
/// <summary> /// Returns code for expand-code equality check of two GMV parts. /// </summary> /// <param name="S">Specification (used for floating points types, output language, GMV).</param> /// <param name="cgd">Output goes here.</param> /// <param name="groupIdx">The group to generate code for.</param> /// <param name="src1">Name of source array 1.</param> /// <param name="src2">Name of source array 2.</param> /// <param name="epsilon">Name of epsilon variable.</param> protected static string GetExpandGmvEqualsCode(Specification S, CGdata cgd, int groupIdx, string src1, string src2, string epsilon) { StringBuilder SB = new StringBuilder(); string TRUE = CodeUtil.GetTrueValue(S); string FALSE = CodeUtil.GetFalseValue(S); for (int i = 0; i < S.m_GMV.Group(groupIdx).Length; i++) SB.Append("\t\tif (((" + src1 + "[" + i + "] - " + src2 + "[" + i + "]) < -" + epsilon + ") || ((" + src1 + "[" + i + "] - " + src2 + "[" + i + "]) > " + epsilon + ")) return " + FALSE + ";\n"); SB.Append("\treturn " + TRUE + ";\n"); return SB.ToString(); }
} // end of GetFunctionName() /// <summary> /// Returns the name of a generated function (for example <c>gp_mv_mv</c>). /// The function is found by looking through all G25.FGS in the Specification. /// /// If the function is not found, a fictional name is returned, i.e. "missingFunction_" + functionName. /// This name will then show up in the generated code, which will not compile as a result. /// /// If the function is not found, this is also enlisted in cgd.m_missingDependencies. /// Call cgd.PrintMissingDependencies() should be called to report the missing dependencies /// to the end-user. /// </summary> /// <param name="S">The spec.</param> /// <param name="cgd">Missing dependencies go into cgd.m_missingDependencies.</param> /// <param name="functionName">Basic name of the function to be found.</param> /// <param name="argumentTypes">Names of the arguments types (not mangled).</param> /// <param name="FT">Floating point type.</param> /// <param name="metricName">(optional, can be null for don't care)</param> /// <returns>The mangled name of the function.</returns> public static string GetDependency(Specification S, CGdata cgd, string functionName, string[] argumentTypes, G25.FloatType FT, string metricName) { string returnTypeName = null; return(GetDependency(S, cgd, functionName, argumentTypes, returnTypeName, FT, metricName)); }
/// <summary> /// Generates functions which compute parts of the application of a general outermorphism to a general multivector. /// /// This function should be called early on in the code generation process, at least /// before any of the <c>???()</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 WriteGomParts(Specification S, CGdata cgd) { if (S.m_GOM == null) { return; // nothing to do if GOM not defiend } int nbBaseTabs = (S.OutputCSharpOrJava()) ? 1 : 0; int nbCodeTabs = nbBaseTabs + 1; G25.GMV gmv = S.m_GMV; G25.GOM gom = S.m_GOM; string nameGOM = "O"; string nameSrcGMV = "A"; string nameDstGMV = "C"; // get symbolic multivector value RefGA.Multivector[] M1 = null; { bool ptr = (S.OutputC()); int allGroups = -1; M1 = G25.CG.Shared.Symbolic.GMVtoSymbolicMultivector(S, gmv, nameSrcGMV, 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>(); // loop over all groups of the GMV, multiply with GOM, and assign the result for (int srcGroup = 0; srcGroup < gmv.NbGroups; srcGroup++) { RefGA.Multivector inputValue = M1[srcGroup]; if (inputValue.IsScalar()) { continue; } // Replace each basis blade in 'inputValue' with its value under the outermorphism. RefGA.Multivector returnValue = RefGA.Multivector.ZERO; // returnValue = gom * gmv[srcGroup] for (int i = 0; i < inputValue.BasisBlades.Length; i++) { // get input blade and domain for that grade RefGA.BasisBlade inputBlade = inputValue.BasisBlades[i]; RefGA.BasisBlade[] domainBlades = gom.DomainForGrade(inputBlade.Grade()); for (int c = 0; c < domainBlades.Length; c++) { // if a match is found in the domain, add range vector to m_returnValue if (domainBlades[c].bitmap == inputBlade.bitmap) { bool ptr = (S.OutputC()); RefGA.Multivector omColumnValue = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(S, gom.DomainSmvForGrade(inputBlade.Grade())[c], nameGOM, ptr); RefGA.Multivector inputBladeScalarMultiplier = new RefGA.Multivector(new RefGA.BasisBlade(inputBlade, 0)); RefGA.Multivector domainBladeScalarMultiplier = new RefGA.Multivector(new RefGA.BasisBlade(domainBlades[c], 0)); returnValue = RefGA.Multivector.Add(returnValue, RefGA.Multivector.gp( RefGA.Multivector.gp(omColumnValue, inputBladeScalarMultiplier), domainBladeScalarMultiplier)); break; // no need to search the other domainBlades too } } } // end of 'compute return value' // assign returnValue to various groups of the gmv for (int dstGroup = 0; dstGroup < gmv.NbGroups; dstGroup++) { bool mustCast = false; bool writeZeros = false; // no need to generate "+= 0.0;" int dstBaseIdx = 0; string code = G25.CG.Shared.CodeUtil.GenerateGMVassignmentCode(S, FT, mustCast, gmv, nameDstGMV, dstGroup, dstBaseIdx, returnValue, nbCodeTabs, writeZeros); string funcName = GetGomPartFunctionName(S, FT, srcGroup, dstGroup); cgd.m_gmvGomPartFuncNames[new Tuple <string, string>(FT.type, funcName)] = (code.Length > 0); if (code.Length == 0) { continue; } if (!S.m_GMV.IsGroupedByGrade(S.m_dimension)) { code = code.Replace("=", "+="); } // check if code was already generated, and, if so, reuse it if (generatedCode.ContainsKey(code)) { // ready generated: call that function code = "\t" + generatedCode[code] + "(" + nameGOM + ", " + nameSrcGMV + ", " + nameDstGMV + ");\n"; } else { // not generated yet: remember code -> function generatedCode[code] = funcName; } // write comment string comment = "Computes the partial application of a general outermorphism to a general multivector"; string OM_PTR = ""; if (S.OutputC()) { OM_PTR = "*"; } else if (S.OutputCpp()) { OM_PTR = "&"; } string ACCESS = ""; if (S.OutputJava()) { ACCESS = "protected 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.GetMangledName(S, gom.Name) + " " + OM_PTR + nameGOM + ", " + CONST + FT.type + ARR + nameSrcGMV + ", " + FT.type + ARR + nameDstGMV + ")"; 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 dest GMV groups } // end of loop over all source GMV groups } // end of loop over all float types } // end of function WriteGomParts()
/// <summary> /// Returns the name of a generated function (for example <c>gp_mv_mv</c>). /// The function is found by looking through all G25.FGS in the Specification. /// /// If the function is not found, a fictional name is returned, i.e. "missingFunction_" + functionName. /// This name will then show up in the generated code, which will not compile as a result. /// /// If the function is not found, this is also enlisted in cgd.m_missingDependencies. /// Call cgd.PrintMissingDependencies() should be called to report the missing dependencies /// to the end-user. /// </summary> /// <param name="S">The spec.</param> /// <param name="cgd">Missing dependencies go into cgd.m_missingDependencies.</param> /// <param name="functionName">Basic name of the function to be found.</param> /// <param name="argumentTypes">Names of the arguments types (not mangled).</param> /// <param name="returnTypeName">Name of the return type (can be null or "" for default return type).</param> /// <param name="FT">Floating point type.</param> /// <param name="metricName">(optional, can be null for don't care)</param> /// <returns>The mangled name of the function.</returns> public static string GetDependency(Specification S, CGdata cgd, string functionName, string[] argumentTypes, string returnTypeName, G25.FloatType FT, string metricName) { // bool returnTrueName = dependent on cgd.mode try { return GetFunctionName(S, functionName, argumentTypes, returnTypeName, FT, metricName); } catch (DependencyException) { // function not found, return a fictional name, and remember dependency G25.fgs F = null; { // get name of dep, and make sure it does not get mangled string outputName = functionName + cgd.GetDontMangleUniqueId(); if (returnTypeName != null) outputName = outputName + "_returns_" + returnTypeName; // add dependency to list of missing deps: string[] argVarNames = null; Dictionary<String, String> options = null; string comment = null; G25.fgs tmpF = new G25.fgs(functionName, outputName, returnTypeName, argumentTypes, argVarNames, new String[] { FT.type }, metricName, comment, options); F = cgd.AddMissingDependency(S, tmpF); } return cgd.m_dependencyPrefix + F.OutputName; } }
/// <summary> /// Constructor that allows you to set StringBuilders for each possible destination /// of the generated code (decl, def, inline def). /// </summary> /// <param name="cgd"></param> /// <param name="declSB"></param> /// <param name="defSB"></param> /// <param name="inlineDefSB"></param> public CGdata(CGdata cgd, StringBuilder declSB, StringBuilder defSB, StringBuilder inlineDefSB) : this(cgd) { m_declSB = declSB; m_defSB = defSB; m_inlineDefSB = inlineDefSB; }
/// <summary> /// The user may have requested a return type (F.ReturnTypeName). /// In that case, the type with the same name is found, or an exception /// is thrown if it does not exists. /// /// Otherwise, finds the (tightest, best) return type for a function 'F' which /// returning the (symbolic) value 'value'. /// This may or may not result in an SMV being found. If no /// type is found and the return type is a scalar, then a floating /// point type may be returned. /// /// If no SMV type is found, then a new type is created, and an exception /// is thrown which described the missing type. /// </summary> /// <param name="S">The specification (used to find SMVs)</param> /// <param name="cgd">Not used currently.</param> /// <param name="F">Function description (used for user-specified return type).</param> /// <param name="FT">Floating point type used in function.</param> /// <param name="value">The symbolic return value.</param> /// <returns>The SMV, FloatType or null if none found.</returns> public static G25.VariableType GetReturnType(Specification S, CGdata cgd, G25.fgs F, FloatType FT, RefGA.Multivector value) { if ((F.ReturnTypeName != null) && (F.ReturnTypeName.Length > 0)) { // The user specified a return type G25.SMV returnSmv = S.GetSMV(F.ReturnTypeName); // is it a SMV? if (returnSmv != null) return returnSmv; G25.FloatType returnFT = S.GetFloatType(F.ReturnTypeName); // is it a specific float? if (returnFT != null) return FT; //returnFT; else if (F.ReturnTypeName == G25.XML.XML_SCALAR) // is it a unspecified float? return FT; // type does not exist: abort (TODO: error message) else throw new G25.UserException("Non-existant user-specified return type: " + F.ReturnTypeName, XML.FunctionToXmlString(S, F)); // non-existant return type } else { G25.VariableType RT = FindTightestMatch(S, value, FT); if (RT != null) return RT; else return CreateSyntheticSMVtype(S, cgd, FT, value); } }
/// <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 }
/// <summary> /// Returns the SMV type that can hold an image of a basis vector. /// </summary> public static G25.SMV GetRangeVectorType(Specification S, G25.FloatType FT, CGdata cgd, G25.SOM som) { RefGA.Multivector rangeVectorValue = new RefGA.Multivector(som.RangeVectors); G25.SMV rangeVectorType = (G25.SMV)G25.CG.Shared.SpecializedReturnType.FindTightestMatch(S, rangeVectorValue, FT); if (rangeVectorType == null) // type is missing, add it and tell user to add it to XML { rangeVectorType = (G25.SMV)G25.CG.Shared.SpecializedReturnType.CreateSyntheticSMVtype(S, cgd, FT, rangeVectorValue); } return rangeVectorType; }
/// <summary> /// Writes functions for the copying, adding, subtracting, negating, scaling /// inverse scaling and Hadamard product of general multivectors, on a group by group basis. /// /// Internally the function loops over all float types, and over all operations (8 in total) /// to generate all code. /// /// This function should be called early on in the code generation process, at least /// before any of the <c>Get....Code()</c> functions is called. /// </summary> /// <param name="S">Specification (used for floating points types, output language, GMV).</param> /// <param name="cgd">Output goes here.</param> public static void WriteCANSparts(Specification S, CGdata cgd) { G25.GMV gmv = S.m_GMV; string srcName1 = "A"; string srcName2 = "B"; string dstName = "C"; string epsilonName = "eps"; string scaleName = "s"; bool ptr = true; int allGroups = -1; bool mustCast = false; int nbBaseTabs = (S.OutputCSharpOrJava()) ? 1 : 0; int nbCodeTabs = nbBaseTabs + 1; bool writeZeros = false; // get two symbolic multivectors (with different symbolic names): RefGA.Multivector[] M1 = null, M2 = null; if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) { // M1 and M2 and only required for full code expansion M1 = G25.CG.Shared.Symbolic.GMVtoSymbolicMultivector(S, gmv, srcName1, ptr, allGroups); M2 = G25.CG.Shared.Symbolic.GMVtoSymbolicMultivector(S, gmv, srcName2, ptr, allGroups); } RefGA.Multivector scaleM = new RefGA.Multivector(scaleName); foreach (G25.FloatType FT in S.m_floatTypes) { // map from code fragment to name of function Dictionary<string, string> generatedCode = new Dictionary<string, string>(); for (int g1 = 0; g1 < gmv.NbGroups; g1++) { int g2 = g1; const int COPY = 0; const int COPY_MUL = 1; const int COPY_DIV = 2; const int ADD = 3; const int SUB = 4; const int NEG = 5; const int ADD2 = 6; const int SUB2 = 7; const int HP = 8; const int IHP = 9; const int EQUALS = 10; const int ZERO = 11; const int NB_OPS = 12; for (int op = 0; op < NB_OPS; op++) { // get value of operation, name of function: RefGA.Multivector value = null; String funcName = null; String comment = null; String code = null; // code depends on code generation mode (expand or run-time) switch (op) { case COPY: if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) value = M1[g1]; else if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) code = GetRuntimeGmvCopyCode(S, cgd, g1, srcName1, dstName); funcName = GetCopyPartFunctionName(S, FT, g1); comment = "copies coordinates of group " + g1; break; case COPY_MUL: if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) value = RefGA.Multivector.gp(scaleM, M1[g1]); else if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) code = GetRuntimeGmvCopyMulDivCode(S, cgd, g1, srcName1, dstName, scaleName, "*"); funcName = GetCopyMulPartFunctionName(S, FT, g1); comment = "copies and multiplies (by " + scaleName + ") coordinates of group " + g1; break; case COPY_DIV: if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) value = RefGA.Multivector.gp(M1[g1], scaleM); else if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) code = GetRuntimeGmvCopyMulDivCode(S, cgd, g1, srcName1, dstName, scaleName, "/"); funcName = GetCopyDivPartFunctionName(S, FT, g1); comment = "copies and divides (by " + scaleName + ") coordinates of group " + g1; break; case ADD: if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) value = M1[g1]; else if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) code = GetRuntimeGmvAddSubNegCode(S, cgd, g1, srcName1, dstName, "+= "); funcName = GetAddPartFunctionName(S, FT, g1); comment = "adds coordinates of group " + g1 + " from variable " + srcName1 + " to " + dstName; break; case SUB: if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) value = M1[g1]; else if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) code = GetRuntimeGmvAddSubNegCode(S, cgd, g1, srcName1, dstName, "-= "); funcName = GetSubPartFunctionName(S, FT, g1); comment = "subtracts coordinates of group " + g1 + " in variable " + srcName1 + " from " + dstName; break; case NEG: if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) value = RefGA.Multivector.Negate(M1[g1]); else if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) code = GetRuntimeGmvAddSubNegCode(S, cgd, g1, srcName1, dstName, "= -"); funcName = GetNegPartFunctionName(S, FT, g1); comment = "negate coordinates of group " + g1 + " of variable " + srcName1; break; case ADD2: if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) value = RefGA.Multivector.Add(M1[g1], M2[g2]); else if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) code = GetRuntimeGmvAdd2Sub2HpCode(S, cgd, g1, srcName1, srcName2, dstName, "+"); funcName = GetAdd2PartFunctionName(S, FT, g1); comment = "adds coordinates of group " + g1 + " of variables " + srcName1 + " and " + srcName2; break; case SUB2: if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) value = RefGA.Multivector.Subtract(M1[g1], M2[g2]); else if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) code = GetRuntimeGmvAdd2Sub2HpCode(S, cgd, g1, srcName1, srcName2, dstName, "-"); funcName = GetSub2PartFunctionName(S, FT, g1); comment = "subtracts coordinates of group " + g1 + " of variables " + srcName1 + " from " + srcName2; break; case HP: if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) { value = RefGA.Multivector.HadamardProduct(M1[g1], M2[g2]); RefGA.Multivector correctedValue = RefGA.Multivector.InverseHadamardProduct(value, S.m_GMV.ToMultivectorValue()); value = correctedValue; } else if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) code = GetRuntimeGmvAdd2Sub2HpCode(S, cgd, g1, srcName1, srcName2, dstName, "*"); funcName = GetHadamardProductPartFunctionName(S, FT, g1); comment = "performs coordinate-wise multiplication of coordinates of group " + g1 + " of variables " + srcName1 + " and " + srcName2; break; case IHP: if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) { value = RefGA.Multivector.InverseHadamardProduct(M1[g1], M2[g2]); RefGA.Multivector correctedValue = RefGA.Multivector.InverseHadamardProduct(value, S.m_GMV.ToMultivectorValue()); value = correctedValue; } else if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) code = GetRuntimeGmvAdd2Sub2HpCode(S, cgd, g1, srcName1, srcName2, dstName, "/"); funcName = GetInverseHadamardProductPartFunctionName(S, FT, g1); comment = "performs coordinate-wise division of coordinates of group " + g1 + " of variables " + srcName1 + " and " + srcName2 + "\n(no checks for divide by zero are made)"; break; case EQUALS: if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) code = GetExpandGmvEqualsCode(S, cgd, g1, srcName1, srcName2, epsilonName); else if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) code = GetRuntimeGmvEqualsCode(S, cgd, g1, srcName1, srcName2, epsilonName); funcName = GetEqualsPartFunctionName(S, FT, g1); comment = "check for equality up to " + epsilonName + " of coordinates of group " + g1 + " of variables " + srcName1 + " and " + srcName2; break; case ZERO: if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) code = GetExpandGmvZeroCode(S, cgd, g1, srcName1, epsilonName); else if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) code = GetRuntimeGmvZeroCode(S, cgd, g1, srcName1, epsilonName); funcName = GetZeroPartFunctionName(S, FT, g1); comment = "checks if coordinates of group " + g1 + " of variable " + srcName1 + " are zero up to " + epsilonName; break; } // code generation for full code expansion if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) { if (!((op == EQUALS) || (op == ZERO))) { // EQUALS and ZERO are different: they generate their own code // get assignment code int dstBaseIdx = 0; code = G25.CG.Shared.CodeUtil.GenerateGMVassignmentCode(S, FT, mustCast, gmv, dstName, g1, dstBaseIdx, value, nbCodeTabs, writeZeros); // replace assignment symbols if required if (op == ADD) code = code.Replace("=", "+="); else if (op == SUB) code = code.Replace("=", "-="); else if (op == COPY_DIV) code = code.Replace("*" + scaleName, "/" + scaleName); } } // check if code was already generated, and, if so, reuse it if (generatedCode.ContainsKey(code)) { // already generated: call that function if ((op == ADD2) || (op == SUB2) || (op == HP) || (op == IHP)) code = new string('\t', nbCodeTabs) + generatedCode[code] + "(" + srcName1 + ", " + srcName2 + ", " + dstName + ");\n"; else if ((op == COPY_MUL) || (op == COPY_DIV)) code = new string('\t', nbCodeTabs) + generatedCode[code] + "(" + srcName1 + ", " + dstName + ", " + scaleName + ");\n"; else if (op == ZERO) code = new string('\t', nbCodeTabs) + "return " + generatedCode[code] + "(" + srcName1 + ", " + epsilonName + ");\n"; else if (op == EQUALS) code = new string('\t', nbCodeTabs) + "return " + generatedCode[code] + "(" + srcName1 + ", " + srcName2 + ", " + epsilonName + ");\n"; else code = new string('\t', nbCodeTabs) + generatedCode[code] + "(" + srcName1 + ", " + dstName + ");\n"; } else { // not generated yet: remember code -> function generatedCode[code] = funcName; } string ACCESS = ""; if (S.OutputJava()) ACCESS = "protected final static "; else if (S.OutputCSharp()) ACCESS = "protected internal static "; string BOOL = CodeUtil.GetBoolType(S); string ARR = (S.OutputCSharpOrJava()) ? "[] " : " *"; string CONST = (S.OutputCSharpOrJava()) ? "" : "const "; string funcDecl; // one or two input args, scale or not? if ((op == ADD2) || (op == SUB2) || (op == HP) || (op == IHP)) funcDecl = ACCESS + "void " + funcName + "(" + CONST + FT.type + ARR + srcName1 + ", " + CONST + FT.type + ARR + srcName2 + ", " + FT.type + ARR + dstName + ")"; else if ((op == COPY_MUL) || (op == COPY_DIV)) funcDecl = ACCESS + "void " + funcName + "(" + CONST + FT.type + ARR + srcName1 + ", " + FT.type + ARR + dstName + ", " + FT.type + " " + scaleName + ")"; else if (op == ZERO) funcDecl = ACCESS + BOOL + " " + funcName + "(" + CONST + FT.type + ARR + srcName1 + ", " + FT.type + " " + epsilonName + ")"; else if (op == EQUALS) funcDecl = ACCESS + BOOL + " " + funcName + "(" + CONST + FT.type + ARR + srcName1 + ", " + CONST + FT.type + ARR + srcName2 + ", " + FT.type + " " + epsilonName + ")"; else funcDecl = ACCESS + "void " + funcName + "(" + CONST + FT.type + ARR + srcName1 + ", " + FT.type + ARR + dstName + ")"; 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); } // append func body: 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 the grade of 'A' } // end of loop over all float types }
/// <returns>A unique name for the testing function of 'funcName'.</returns> public static string GetTestingFunctionName(Specification S, CGdata cgd, string funcName) { if (S.OutputC()) return "test_" + funcName; else return "test_" + funcName + cgd.GetDontMangleUniqueId(); }
/// <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()
/// <summary> /// Writes pieces of code to <c>cgd</c> which compute the geometric product of general multivectors, /// on a group by group basis. The function is output language aware. /// </summary> /// <param name="S">Specification (used for output language, GMV).</param> /// <param name="cgd">Result goes here, and <c>cgd.m_gmvGPpartFuncNames</c> is set.</param> public static void WriteGmvGpParts(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 = 1 + nbBaseTabs; bool writeZeros = false; // get two symbolic multivectors (with different symbolic names): RefGA.Multivector[] M1 = null, M2 = null; if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) { M1 = G25.CG.Shared.Symbolic.GMVtoSymbolicMultivector(S, gmv, name1, ptr, allGroups); M2 = G25.CG.Shared.Symbolic.GMVtoSymbolicMultivector(S, gmv, name2, ptr, allGroups); } foreach (G25.FloatType FT in S.m_floatTypes) { bool fromOutsideRuntimeNamespace = true; string runtimeComputeGpFuncName = GetRuntimeComputeGpFuncName(S, FT, fromOutsideRuntimeNamespace); int metricId = 0; foreach (G25.Metric M in S.m_metric) { // map from code fragment to name of function Dictionary<string, string> generatedCode = new Dictionary<string, string>(); for (int g1 = 0; g1 < gmv.NbGroups; g1++) { for (int g2 = 0; g2 < gmv.NbGroups; g2++) { RefGA.Multivector M3 = null; if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) { M3 = RefGA.Multivector.gp(M1[g1], M2[g2], M.m_metric); // round value if required by metric if (M.m_round) M3 = M3.Round(1e-14); } for (int gd = 0; gd < gmv.NbGroups; gd++) { // get function name string funcName = GetGPpartFunctionName(S, FT, M, g1, g2, gd); // get assignment code string code = ""; // empty string means 'no code for this combo of g1, g2, gd and metric'. if (S.m_gmvCodeGeneration == GMV_CODE.EXPAND) { // code for full expansion int dstBaseIdx = 0; code = G25.CG.Shared.CodeUtil.GenerateGMVassignmentCode(S, FT, mustCast, gmv, name3, gd, dstBaseIdx, M3, nbCodeTabs, writeZeros); // replace '=' with '+=' code = code.Replace("=", "+="); } else if (S.m_gmvCodeGeneration == GMV_CODE.RUNTIME) { // code for runtime geometric product string EMP = (S.OutputCppOrC()) ? "&" : ""; if (!S.m_GMV.IsZeroGP(g1, g2, gd)) { fromOutsideRuntimeNamespace = true; string runtimeGpTableName = GetRuntimeGpTableName(S, M, g1, g2, gd, fromOutsideRuntimeNamespace); if (S.OutputCSharpOrJava()) { string initFunc = S.OutputJava() ? "initRuntimeGpTable" : "InitRuntimeGpTable"; code = "\t\tif(" + runtimeGpTableName + " == null) " + runtimeGpTableName + " = " + initFunc + "(" + metricId + ", " + g1 + ", " + g2 + ", " + gd + ");\n\t"; } code += "\t" + runtimeComputeGpFuncName + "(" + name1 + ", " + name2 + ", " + name3 + ", " + EMP + runtimeGpTableName + ", " + metricId + ", " + g1 + ", " + g2 + ", " + gd + ");\n"; } } // set the function names of parts of the geometric product cgd.m_gmvGPpartFuncNames[new Tuple<string, string, string>(FT.type, M.m_name, funcName)] = (code.Length > 0); if (code.Length > 0) { // check if code was already generated, and, if so, reuse it if ((S.m_gmvCodeGeneration == GMV_CODE.EXPAND) && generatedCode.ContainsKey(code)) { // ready generated: call that function code = new string('\t', nbCodeTabs) + generatedCode[code] + "(" + name1 + ", " + name2 + ", " + name3 + ");\n"; } else { // not generated yet: remember code -> function generatedCode[code] = funcName; } string comment = "Computes the partial geometric product of two multivectors (group " + g1 + " x group " + g2 + " -> group " + gd + ")"; string funcDecl; if (S.OutputCppOrC()) { funcDecl = "void " + funcName + "(const " + FT.type + " *" + name1 + ", const " + FT.type + " *" + name2 + ", " + FT.type + " *" + name3 + ")"; // write comment int nbCommentTabs = nbBaseTabs; new Comment(comment).Write(cgd.m_declSB, S, nbCommentTabs); // emit decl cgd.m_declSB.Append(funcDecl); cgd.m_declSB.AppendLine(";"); } else { string ACCESS = (S.OutputJava()) ? "protected final static " : "protected internal static "; funcDecl = ACCESS + "void " + funcName + "(" + FT.type + "[] " + name1 + ", " + FT.type + "[] " + name2 + ", " + FT.type + "[] " + name3 + ")"; // write comment int nbCommentTabs = nbBaseTabs; new Comment(comment).Write(cgd.m_defSB, S, nbCommentTabs); } // 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 'if code not empty' } // end of loop over the grade of 'C' } // end of loop over the grade of 'B' } // end of loop over the grade of 'A' metricId++; } // end of loop over all metrics } // end of loop over all float types }
/// <summary> /// Returns the name of a generated function (for example <c>gp_mv_mv</c>). /// The function is found by looking through all G25.FGS in the Specification. /// /// If the function is not found, a fictional name is returned, i.e. "missingFunction_" + functionName. /// This name will then show up in the generated code, which will not compile as a result. /// /// If the function is not found, this is also enlisted in cgd.m_missingDependencies. /// Call cgd.PrintMissingDependencies() should be called to report the missing dependencies /// to the end-user. /// </summary> /// <param name="S">The spec.</param> /// <param name="cgd">Missing dependencies go into cgd.m_missingDependencies.</param> /// <param name="functionName">Basic name of the function to be found.</param> /// <param name="argumentTypes">Names of the arguments types (not mangled).</param> /// <param name="FT">Floating point type.</param> /// <param name="metricName">(optional, can be null for don't care)</param> /// <returns>The mangled name of the function.</returns> public static string GetDependency(Specification S, CGdata cgd, string functionName, string[] argumentTypes, G25.FloatType FT, string metricName) { string returnTypeName = null; return GetDependency(S, cgd, functionName, argumentTypes, returnTypeName, FT, metricName); }