} // end of function WriteDualParts() /// <summary> /// Returns the code for dualization wrt to whole space using metric <c>M</c>. /// The code is composed of calls to functions generated by <c>WriteGmvDualParts()</c>. /// /// This function uses <c>cdg.m_gmvDualPartFuncNames</c>, but only to check whether a /// geometric product of some group with the pseudoscalar will get non-zero results in some /// other group. /// /// The returned code is only the body. The function declaration is not included. /// </summary> /// <param name="S">Specification of algebra (used for general multivector type, output language).</param> /// <param name="cgd">Used for <c>m_gmvDualPartFuncNames</c>.</param> /// <param name="FT">Floating point type.</param> /// <param name="M">The metric of the dual.</param> /// <param name="FAI">Info about function arguments</param> /// <param name="resultName">Name of variable where the result goes (in the generated code).</param> /// <param name="dual">When true, 'dual' is generated, otherwise, 'undual' is generated.</param> /// <returns>code for the requested product type.</returns> public static string GetDualCode(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.Metric M, G25.CG.Shared.FuncArgInfo[] FAI, string resultName, bool dual) { if (S.OutputCppOrC()) { return(GetDualCodeCppOrC(S, cgd, FT, M, FAI, resultName, dual)); } else { return(GetDualCodeCSharpOrJava(S, cgd, FT, M, FAI, resultName, dual)); } }
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()
} // 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> /// Writes any geometric product based product for general multivectors, /// based on gp parts code. /// </summary> /// <param name="SB"></param> /// <param name="S"></param> /// <param name="cgd"></param> /// <param name="FT"></param> /// <param name="M"></param> /// <param name="FAI"></param> /// <param name="F"></param> /// <param name="comment"></param> /// <param name="declOnly"></param> /// <param name="productType"></param> /// <returns>name of generated function</returns> public static string WriteGMVgpFunction(Specification S, G25.CG.Shared.CGdata cgd, FloatType FT, G25.Metric M, G25.CG.Shared.FuncArgInfo[] FAI, G25.fgs F, Comment comment, G25.CG.Shared.GPparts.ProductTypes productType) { // setup instructions System.Collections.Generic.List <G25.CG.Shared.Instruction> I = new System.Collections.Generic.List <G25.CG.Shared.Instruction>(); int nbTabs = 1; // write this function: string code = G25.CG.Shared.GPparts.GetGPcode(S, cgd, FT, M, productType, FAI, fgs.RETURN_ARG_NAME); // add one instruction (verbatim code) I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, code)); // because of lack of overloading, function names include names of argument types G25.fgs CF = G25.CG.Shared.Util.AppendTypenameToFuncName(S, FT, F, FAI); // setup return type and argument: string returnTypeName = null; G25.CG.Shared.FuncArgInfo returnArgument = null; if (productType == G25.CG.Shared.GPparts.ProductTypes.SCALAR_PRODUCT) { // return scalar returnTypeName = FT.type; } else { // return GMV (in C, via 'return argument') returnTypeName = FT.GetMangledName(S, S.m_GMV.Name); if (S.OutputC()) { returnArgument = new G25.CG.Shared.FuncArgInfo(S, CF, -1, FT, S.m_GMV.Name, false); // false = compute value } } string funcName = CF.OutputName; // FAI[0].MangledTypeName; //CF.ArgumentTypeNames[0] = CF.ArgumentTypeNames[0] + G25.CG.Shared.Main.IF_SUFFIX; // write function bool inline = false; // never inline GMV functions bool staticFunc = Functions.OutputStaticFunctions(S); G25.CG.Shared.Functions.WriteFunction(S, cgd, F, inline, staticFunc, returnTypeName, funcName, returnArgument, FAI, I, comment); return(funcName); } // end of WriteGMVgpFunction
} // end of WriteGMVnormFunction /// <summary> /// Writes any versor application function for general multivectors, /// based on norm2 and geometric product. /// </summary> /// <param name="SB"></param> /// <param name="S"></param> /// <param name="cgd"></param> /// <param name="FT"></param> /// <param name="M"></param> /// <param name="FAI"></param> /// <param name="F"></param> /// <param name="comment"></param> /// <param name="declOnly"></param> /// <param name="productType"></param> /// <returns>name of generated function.</returns> public static string WriteGMVapplyVersorFunction(Specification S, G25.CG.Shared.CGdata cgd, FloatType FT, G25.Metric M, G25.CG.Shared.FuncArgInfo[] FAI, G25.fgs F, Comment comment, G25.CG.Shared.GPparts.ApplyVersorTypes AVtype) { // setup instructions System.Collections.Generic.List <G25.CG.Shared.Instruction> I = new System.Collections.Generic.List <G25.CG.Shared.Instruction>(); int nbTabs = 1; // write this function: string code = G25.CG.Shared.GPparts.GetVersorApplicationCode(S, cgd, FT, M, AVtype, FAI, fgs.RETURN_ARG_NAME); // add one instruction (verbatim code) I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, code)); // because of lack of overloading, function names include names of argument types G25.fgs CF = G25.CG.Shared.Util.AppendTypenameToFuncName(S, FT, F, FAI); // Console.WriteLine("Ft = " + FT.type + " funname = " + CF.OutputName); string funcName = CF.OutputName; // setup return type and argument: string returnTypeName = FT.GetMangledName(S, S.m_GMV.Name); G25.CG.Shared.FuncArgInfo returnArgument = null; if (S.OutputC()) { returnArgument = new G25.CG.Shared.FuncArgInfo(S, CF, -1, FT, S.m_GMV.Name, false); // false = compute value } // write function bool inline = false; // never inline GMV functions bool staticFunc = Functions.OutputStaticFunctions(S); G25.CG.Shared.Functions.WriteFunction(S, cgd, F, inline, staticFunc, returnTypeName, CF.OutputName, returnArgument, FAI, I, comment); return(funcName); }
} // end of WriteGMVigpFunction /// <summary> /// Writes any norm function for general multivectors, based on gp parts code. /// </summary> /// <param name="SB"></param> /// <param name="S"></param> /// <param name="cgd"></param> /// <param name="FT"></param> /// <param name="M"></param> /// <param name="FAI"></param> /// <param name="F"></param> /// <param name="comment"></param> /// <param name="declOnly"></param> /// <param name="squared"></param> /// <returns>name of generated function.</returns> public static string WriteGMVnormFunction(Specification S, G25.CG.Shared.CGdata cgd, FloatType FT, G25.Metric M, G25.CG.Shared.FuncArgInfo[] FAI, G25.fgs F, Comment comment, bool squared) { // setup instructions System.Collections.Generic.List <G25.CG.Shared.Instruction> I = new System.Collections.Generic.List <G25.CG.Shared.Instruction>(); int nbTabs = 1; // because of lack of overloading, function names include names of argument types G25.fgs CF = G25.CG.Shared.Util.AppendTypenameToFuncName(S, FT, F, FAI); string funcName = CF.OutputName; // get return info G25.SMV returnType = null; string returnTypeName = null; G25.CG.Shared.FuncArgInfo returnArgument = null; { // try to get scalar type returnType = S.GetScalarSMV(); if (returnType == null) { returnTypeName = FT.type; } else { if (S.OutputC()) { returnArgument = new G25.CG.Shared.FuncArgInfo(S, CF, -1, FT, returnType.Name, false); // false = compute value } returnTypeName = FT.GetMangledName(S, returnType.GetName()); } } // write this function: string code = G25.CG.Shared.GPparts.GetNormCode(S, cgd, FT, M, squared, FAI, returnType, G25.fgs.RETURN_ARG_NAME); // add the verbatim code I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, code)); // write function bool inline = false; // never inline GMV functions bool staticFunc = Functions.OutputStaticFunctions(S); G25.CG.Shared.Functions.WriteFunction(S, cgd, F, inline, staticFunc, returnTypeName, funcName, returnArgument, FAI, I, comment); return(funcName); } // end of WriteGMVnormFunction
/// <summary> /// Must be called before CompleteFGS(), CheckDepencies() or WriteFunction() is called. /// Subclass can override, but if so, must always call superclass version of Init() /// </summary> /// <param name="S"></param> /// <param name="F"></param> /// <param name="cgd">Where the generate code goes.</param> public virtual void Init(Specification S, G25.fgs F, G25.CG.Shared.CGdata cgd) { m_specification = S; m_fgs = F; m_cgd = cgd; m_gmv = m_specification.m_GMV; m_G25M = m_specification.GetMetric(m_fgs.MetricName); m_M = m_G25M.m_metric; m_sane = true; }
/// <summary> /// Writes the declaration/definitions of 'F' to StringBuffer 'SB', taking into account parameters specified in specification 'S'. /// </summary> public override void WriteFunction() { // get metric G25.Metric G25M = m_specification.GetMetric(m_fgs.MetricName); //RefGA.Metric M = G25M.m_metric; bool isUnit = IsApplyUnitVersor(m_fgs) || IsApplyVersorWI(m_fgs); foreach (string floatName in m_fgs.FloatNames) { FloatType FT = m_specification.GetFloatType(floatName); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); // generate comment string warningComment = (isUnit) ? " Only gives the correct result when the versor has a positive squared norm.\n" : ""; Comment comment = new Comment( m_fgs.AddUserComment("Returns " + FAI[0].Name + " * " + FAI[1].Name + " * " + ((isUnit) ? "reverse" : "inverse") + "(" + FAI[0].Name + ") using " + m_G25M.m_name + " metric." + warningComment)); if (m_gmvFunc) { // generate function over GMVs // determine what type of function is requested: G25.CG.Shared.GPparts.ApplyVersorTypes AVtype; if (IsApplyVersor(m_fgs)) { AVtype = G25.CG.Shared.GPparts.ApplyVersorTypes.INVERSE; } else if (IsApplyUnitVersor(m_fgs)) { AVtype = G25.CG.Shared.GPparts.ApplyVersorTypes.REVERSE; } else { AVtype = G25.CG.Shared.GPparts.ApplyVersorTypes.EXPLICIT_INVERSE; } // generate code: m_funcName[FT.type] = G25.CG.Shared.GmvGpParts.WriteGMVapplyVersorFunction(m_specification, m_cgd, FT, G25M, FAI, m_fgs, comment, AVtype); } else { // write specialized function: // setup instructions System.Collections.Generic.List <G25.CG.Shared.Instruction> I = new System.Collections.Generic.List <G25.CG.Shared.Instruction>(); { int nbTabs = 1; bool mustCast = false; bool n2Ptr = false; bool declareN2 = true; if (!isUnit) { // n2 = reverse(versor) * versor I.Add(new G25.CG.Shared.AssignInstruction(nbTabs, FT, FT, mustCast, m_n2Value, m_normSquaredName, n2Ptr, declareN2)); } //bool transformedPtr = !(FAI[1].Type is G25.FloatType); //bool declareTransformed = false; if (isUnit) { // result = versor * X * reverse(versor) I.Add(new G25.CG.Shared.ReturnInstruction(nbTabs, m_returnType, FT, mustCast, m_transformedValue)); } else { // result = versor * X * reverse(versor) / (reverse(versor).versor) I.Add(new G25.CG.Shared.ReturnInstruction(nbTabs, m_returnType, FT, mustCast, m_transformedValue, "/", new RefGA.Multivector(m_normSquaredName))); } } // because of lack of overloading, function names include names of argument types G25.fgs CF = G25.CG.Shared.Util.AppendTypenameToFuncName(m_specification, FT, m_fgs, FAI); m_funcName[FT.type] = CF.OutputName; bool staticFunc = Functions.OutputStaticFunctions(m_specification); G25.CG.Shared.Functions.WriteFunction(m_specification, m_cgd, CF, m_specification.m_inlineFunctions, staticFunc, CF.OutputName, FAI, I, comment); } } } // end of WriteFunction
/// <param name="S"></param> /// <param name="FT"></param> /// <param name="M"></param> /// <param name="d">1 -> generate dual, d = 0 -> generate undual</param> /// <param name="g1"></param> /// <param name="gd"></param> /// <param name="name1"></param> /// <param name="name2"></param> /// <param name="name3"></param> /// <returns>The code to compute a (un)dual at runtime using the geometric product tables.</returns> public static string GetRuntimeDualCode(G25.Specification S, G25.FloatType FT, G25.Metric M, int d, int g1, int gd, string name1, string name2, string name3) { // get pseudoscalar RefGA.Multivector I = RefGA.Multivector.GetPseudoscalar(S.m_dimension); if (d == 1) // if dual: use inverse I { I = RefGA.Multivector.VersorInverse(I, M.m_metric); } // get grade/group of pseudoscalar in GMV int g2 = S.m_GMV.GetGroupIdx(I.BasisBlades[0]); // get sign of pseudo scalar basis blade in GMV: double IbladeSign = S.m_GMV.Group(g2)[0].scale; string tmpArrayCode; if (S.OutputCppOrC()) { tmpArrayCode = "\t" + FT.type + " " + name2 + "[1] = {" + FT.DoubleToString(S, IbladeSign * I.BasisBlades[0].scale) + "};\n"; } else { tmpArrayCode = "\t\t" + FT.type + "[] " + name2 + " = new " + FT.type + "[]{" + FT.DoubleToString(S, IbladeSign * I.BasisBlades[0].scale) + "};\n\t"; } return (tmpArrayCode + "\t" + GPparts.GetGPpartFunctionName(S, FT, M, g1, g2, gd) + "(" + name1 + ", " + name2 + ", " + name3 + ");\n"); }
/// <summary> /// Returns the name of a partial undual function. /// </summary> /// <param name="FT">Float type (used for mangled name).</param> /// <param name="M">Metric of dual.</param> /// <param name="gi">Grade/group of input.</param> /// <param name="go">Grade/group of output.</param> /// <returns>name of a partial geometric product function.</returns> public static string GetUndualPartFunctionName(Specification S, G25.FloatType FT, G25.Metric M, int gi, int go) { return(FT.GetMangledName(S, "undual") + "_" + M.m_name + "_" + gi + "_" + go); }