/// <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> /// Writes code for return m_name. /// </summary> /// <param name="SB">Where the code goes.</param> /// <param name="S">Specification of algebra.</param> /// <param name="cgd">Not used yet.</param> public override void Write(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd) { if (m_type is G25.FloatType) { AppendTabs(SB); // Temp hack to override the float type: G25.FloatType FT = m_floatType; //m_type as G25.FloatType; // Should postops still be applied? ApplyPostOp(S, plugins, cog, BL, valueStr); // Not required so far? SB.AppendLine(CodeUtil.GenerateScalarReturnCode(S, FT, m_mustCast, m_value)); } else if (m_type is G25.SMV) { if (S.OutputC()) { bool ptr = true; bool declareVariable = false; new AssignInstruction(m_nbTabs, m_type, m_floatType, m_mustCast, m_value, G25.fgs.RETURN_ARG_NAME, ptr, declareVariable, m_postOp, m_postOpValue).Write(SB, S, cgd); } else { G25.SMV smv = m_type as G25.SMV; RefGA.BasisBlade[] BL = BasisBlade.GetNonConstBladeList(smv); bool writeZeros = true; string[] valueStr = CodeUtil.GetAssignmentStrings(S, m_floatType, m_mustCast, BL, m_value, writeZeros); // apply post operation (like "/ n2") ApplyPostOp(S, cgd, BL, valueStr); SB.AppendLine(CodeUtil.GenerateReturnCode(S, smv, m_floatType, valueStr, m_nbTabs, writeZeros)); } } }
} // end of GenerateSMVassignmentCode public static string GenerateReturnCode(Specification S, G25.SMV smv, G25.FloatType FT, String[] valueStr, int nbTabs, bool writeZeros) { StringBuilder SB = new StringBuilder(); string smvName = FT.GetMangledName(S, smv.Name); string STATIC_MEMBER_ACCESS = (S.OutputCpp()) ? "::" : "."; SB.Append('\t', nbTabs); SB.Append("return "); if (S.OutputCSharpOrJava()) { SB.Append("new "); } SB.Append(smvName); SB.Append("("); if (valueStr.Length > 0) { SB.AppendLine(smvName + STATIC_MEMBER_ACCESS + SmvUtil.GetCoordinateOrderConstant(S, smv) + ","); } for (int i = 0; i < valueStr.Length; i++) { SB.Append('\t', nbTabs + 2); SB.Append(valueStr[i]); if (i < (valueStr.Length - 1)) { SB.Append(","); } SB.AppendLine(" // " + smv.NonConstBasisBlade(i).ToLangString(S.m_basisVectorNames)); } SB.Append('\t', nbTabs + 1); SB.Append(");"); return(SB.ToString()); }
} // end of function ScalarOpToLangString() /// <summary> /// Converts a <c>RefGA.Symbolic.BinaryScalarOpToLangString</c> to code. /// /// Handles special cases (such as inversion) and understands floating point /// types (e.g., <c>fabsf()</c> is used for floats and <c>fabs()</c> is used for doubles in C. /// </summary> /// <param name="S">Used for output language.</param> /// <param name="FT">Floating point type used.</param> /// <param name="Op">The operation to convert to code.</param> /// <returns>Code for implementing <c>Op</c>c>.</returns> public static string BinaryScalarOpToLangString(G25.Specification S, G25.FloatType FT, RefGA.Symbolic.BinaryScalarOp Op) { string value1Str = ScalarOpValueToLangString(S, FT, Op.value1); string value2Str = ScalarOpValueToLangString(S, FT, Op.value2); return(OpNameToLangString(S, FT, Op.opName) + "(" + value1Str + ", " + value2Str + ")"); } // end of function BinaryScalarOpToLangString()
} // end of WriteSetArray() /// <summary> /// Writes a function to copy the value of one SMV struct to another, for all floating point types. /// </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> public static void WriteSetCopy(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.SMV smv) { cgd.m_defSB.AppendLine(""); //string className = FT.GetMangledName(S, smv.Name); string funcName = GMV.GetSetFuncName(S); bool mustCast = false; G25.fgs F = new G25.fgs(funcName, funcName, "", new string[] { smv.Name }, null, new string[] { FT.type }, null, null, null); // null, null, null = metricName, comment, options F.InitArgumentPtrFromTypeNames(S); bool computeMultivectorValue = false; int nbArgs = 1; G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(S, F, nbArgs, FT, null, computeMultivectorValue); RefGA.Multivector value = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(S, smv, FAI[0].Name, FAI[0].Pointer); string dstName = G25.CG.Shared.SmvUtil.THIS; bool dstPtr = false; bool staticFunc = false; G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd, S.m_inlineSet, staticFunc, "void", null, funcName, null, FAI, FT, mustCast, smv, dstName, dstPtr, value); } // end of WriteSetCopy()
/// <summary> /// Converts a <c>RefGA.Symbolic.UnaryScalarOp</c> to code. /// /// Handles special cases (such as inversion) and understands floating point /// types (e.g., <c>fabsf()</c> is used for floats and <c>fabs()</c> is used for doubles in C. /// </summary> /// <param name="S">Used for output language.</param> /// <param name="FT">Floating point type used.</param> /// <param name="Op">The operation to convert to code.</param> /// <returns>Code for implementing <c>Op</c>c>.</returns> public static string UnaryScalarOpToLangString(G25.Specification S, G25.FloatType FT, RefGA.Symbolic.UnaryScalarOp Op) { string valueStr = ScalarOpValueToLangString(S, FT, Op.value); /*{ * if (!Op.value.IsScalar()) throw new Exception("G25.CG.Shared.BasisBlade.ScalarOpToLangString(): value should be scalar, found: " + Op.value.ToString(S.m_basisVectorNames)); * if (Op.value.IsZero()) valueStr = ScalarToLangString(S, FT, RefGA.BasisBlade.ZERO); * else valueStr = ScalarToLangString(S, FT, Op.value.BasisBlades[0]); * }*/ if (Op.opName == UnaryScalarOp.INVERSE) { if (FT.type == "float") { return("1.0f / (" + valueStr + ")"); } else if (FT.type == "double") { return("1.0 / (" + valueStr + ")"); } else { return(FT.castStr + "1.0 / (" + valueStr + ")"); } } else { return(OpNameToLangString(S, FT, Op.opName) + "(" + valueStr + ")"); } } // end of function ScalarOpToLangString()
} // end of WriteFunctions() /// <summary> /// Writes a simple function which assigns some value based on specialized multivectors or scalars to some variable. /// /// Used by a lot of simple C functions, like gp, op, lc. /// /// Somewhat obsolete (preferably, use the more generic, instruction based WriteFunction()). /// /// </summary> /// <param name="S">Specification of algebra.</param> /// <param name="cgd">Results go into cgd.m_defSB, and so on</param> /// <param name="F">The function generation specification.</param> /// <param name="FT">Default float pointer type.</param> /// <param name="FAI">Info on the arguments of the function.</param> /// <param name="value">The value to assign.</param> /// <param name="comment">Optional comment for function (can be null).</param> public static void WriteSpecializedFunction(Specification S, G25.CG.Shared.CGdata cgd, G25.fgs F, FloatType FT, G25.CG.Shared.FuncArgInfo[] FAI, RefGA.Multivector value, Comment comment) { // get return type (may be a G25.SMV or a G25.FloatType) G25.VariableType returnType = G25.CG.Shared.SpecializedReturnType.GetReturnType(S, cgd, F, FT, value); if (returnType == null) { throw new G25.UserException("Missing return type: " + G25.CG.Shared.BasisBlade.MultivectorToTypeDescription(S, value), XML.FunctionToXmlString(S, F)); } bool ptr = true; string dstName = G25.fgs.RETURN_ARG_NAME; //string dstTypeName = (returnType is G25.SMV) ? FT.GetMangledName((returnType as G25.SMV).Name) : (returnType as G25.FloatType).type; string funcName = F.OutputName; // write comment to declaration if (comment != null) { if (S.OutputCppOrC()) { comment.Write(cgd.m_declSB, S, 0); } else { comment.Write(cgd.m_defSB, S, 0); } } if ((returnType is G25.SMV) && (S.OutputC())) { bool mustCast = false; G25.SMV dstSmv = returnType as G25.SMV; G25.CG.Shared.FuncArgInfo returnArgument = null; returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, FT, dstSmv.Name, false); // false = compute value bool staticFunc = S.OutputCSharpOrJava(); G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd, S.m_inlineFunctions, staticFunc, "void", null, funcName, returnArgument, FAI, FT, mustCast, dstSmv, dstName, ptr, value); } else { G25.FloatType returnFT = ((returnType as G25.FloatType) == null) ? FT : (returnType as G25.FloatType); bool mustCast = false; for (int i = 0; i < FAI.Length; i++) { mustCast |= returnFT.MustCastIfAssigned(S, FAI[i].FloatType); } bool staticFunc = S.OutputCSharpOrJava(); G25.CG.Shared.Functions.WriteReturnFunction(S, cgd, S.m_inlineSet, staticFunc, funcName, FAI, FT, mustCast, returnType, value); } } // end of WriteSpecializedFunction()
/// <summary> /// Instruction for generating code for an assignment to a variable, with an optional declration of that same variable. /// </summary> /// <param name="nbTabs">How many tabs to put in front of code.</param> /// <param name="T">Type of assigned variable.</param> /// <param name="FT">Floating point type of coordinates of assigned variable. If T is a floating point type, then is equal to T.</param> /// <param name="mustCast">When assigning to variable, should the coordinates be cast to FT?</param> /// <param name="value">The assigned value.</param> /// <param name="name">Name of assigned variable.</param> /// <param name="ptr">Is the assigned variable a pointer?</param> /// <param name="declareVariable">If true, code for declaring the variable is also generated.</param> public AssignInstruction(int nbTabs, G25.VariableType T, G25.FloatType FT, bool mustCast, RefGA.Multivector value, string name, bool ptr, bool declareVariable) : base(nbTabs, T, FT, mustCast, value) { m_name = name; m_ptr = ptr; m_declareVariable = declareVariable; }
/// <summary> /// Instruction for generating code for an assignment to or a return of a variable. /// </summary> /// <param name="nbTabs">How many tabs to put in front of code.</param> /// <param name="T">Type of assigned variable.</param> /// <param name="FT">Floating point type of coordinates of assigned variable.</param> /// <param name="mustCast">When assigning to variable, should the coordinates be cast to FT?</param> /// <param name="value">The assigned value.</param> public AssignOrReturnInstruction(int nbTabs, G25.VariableType T, G25.FloatType FT, bool mustCast, RefGA.Multivector value) : base(nbTabs) { m_type = T; m_floatType = FT; m_mustCast = mustCast; m_value = value; }
/// <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 code for m_name = m_value. /// </summary> /// <param name="SB">Where the code goes.</param> /// <param name="S">Specification of algebra.</param> /// <param name="cgd">Not used yet.</param> public override void Write(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd) { if (m_type is G25.SMV) { G25.SMV dstSmv = m_type as G25.SMV; if (m_declareVariable) { SB.AppendLine("/* cannot yet assign and declare SMV type at the same time */"); } RefGA.BasisBlade[] BL = BasisBlade.GetNonConstBladeList(dstSmv); string[] accessStr = CodeUtil.GetAccessStr(S, dstSmv, m_name, m_ptr); bool writeZeros = true; string[] valueStr = CodeUtil.GetAssignmentStrings(S, m_floatType, m_mustCast, BL, m_value, writeZeros); // apply post operation (like "/ n2") ApplyPostOp(S, cgd, BL, valueStr); SB.AppendLine(CodeUtil.GenerateAssignmentCode(S, accessStr, valueStr, m_nbTabs, writeZeros)); } else if (m_type is G25.FloatType) { // temp hack to override float type. G25.FloatType FT = this.m_floatType; // m_type as G25.FloatType; AppendTabs(SB); if (m_declareVariable) { // also declare the variable right here? // output "/t type " SB.Append(FT.type + " "); } // output name = ....; RefGA.BasisBlade[] BL = new RefGA.BasisBlade[1] { RefGA.BasisBlade.ONE }; String[] accessStr = new String[1] { m_name }; bool writeZeros = true; String[] valueStr = CodeUtil.GetAssignmentStrings(S, FT, m_mustCast, BL, m_value, writeZeros); // apply post operation (like "/ n2") ApplyPostOp(S, cgd, BL, valueStr); SB.AppendLine(CodeUtil.GenerateAssignmentCode(S, accessStr, valueStr, 0, writeZeros)); } else { SB.AppendLine("/* to do: implement " + GetType().ToString() + " for type " + m_type.GetType().ToString() + " */"); } }
/// <summary> /// Returns the code to copy an array of 'nb' floats from 'srcPtrName' to 'dstPtrName'. /// </summary> public static string GetCopyCode(G25.Specification S, G25.FloatType FT, string srcPtrName, string dstPtrName, int nb) { if (nb <= Main.MAX_EXPLICIT_ZERO) { return(GetZeroCodePrefix(S, FT) + GetCopyFuncName(S) + "_" + nb + "(" + dstPtrName + ", " + srcPtrName + ");\n"); } else { return(GetCopyCode(S, FT, srcPtrName, dstPtrName, nb.ToString())); } }
/// <summary> /// Returns the code to set ptrName[0] to ptrName[nb-1] to 0. /// </summary> public static string GetSetToZeroCode(G25.Specification S, G25.FloatType FT, string ptrName, int nb) { if (nb <= Main.MAX_EXPLICIT_ZERO) { return(GetZeroCodePrefix(S, FT) + GetZeroFuncName(S) + "_" + nb + "(" + ptrName + ");\n"); } else { return(GetSetToZeroCode(S, FT, ptrName, nb.ToString())); } }
} // 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)); } }
/// <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]); } } }
} // end of function ScalarToLangString /// <summary> /// Converts scalar part of 'value' to ouput language dependent string. /// </summary> private static string ScalarOpValueToLangString(G25.Specification S, G25.FloatType FT, RefGA.Multivector value) { if (!value.IsScalar()) { throw new Exception("G25.CG.Shared.BasisBlade.ScalarOpValueToLangString(): value should be scalar, found: " + value.ToString(S.m_basisVectorNames)); } if (value.IsZero()) { return(ScalarToLangString(S, FT, RefGA.BasisBlade.ZERO)); } else { return(ScalarToLangString(S, FT, value.BasisBlades[0])); } }
} // end of function BinaryScalarOpToLangString() public static string OpNameToLangString(G25.Specification S, G25.FloatType FT, string opName) { switch (S.m_outputLanguage) { case OUTPUT_LANGUAGE.C: if (FT.type == "float") { return(m_floatOpsC[opName]); } else { return(m_doubleOpsC[opName]); } case OUTPUT_LANGUAGE.CPP: if (FT.type == "float") { return(m_floatOpsCpp[opName]); } else { return(m_doubleOpsCpp[opName]); } case OUTPUT_LANGUAGE.CSHARP: if (FT.type == "float") { return(m_floatOpsCSharp[opName]); } else { return(m_doubleOpsCSharp[opName]); } case OUTPUT_LANGUAGE.JAVA: if (FT.type == "float") { return(m_floatOpsJava[opName]); } else { return(m_doubleOpsJava[opName]); } default: throw new Exception("G25.CG.Shared.BasisBlade.ScalarOpToLangString(): todo: language " + S.GetOutputLanguageString()); } }
/// <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 a function to set an SMV struct to zero, for all floating point types. /// </summary> /// <param name="S">Used for basis vector names and output language.</param> /// <param name="cgd">Results go here. Also intermediate data for code generation. Also contains plugins and cog.</param> private static void WriteSetZero(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.SMV smv) { //if (smv.NbNonConstBasisBlade == 0) return; cgd.m_defSB.AppendLine(""); string funcName = GMV.GetSetFuncName(S); bool mustCast = false; string returnVarName = null; string dstName = G25.CG.Shared.SmvUtil.THIS; bool dstPtr = false; bool staticFunc = false; G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd, S.m_inlineSet, staticFunc, "void", returnVarName, funcName, null, null, FT, mustCast, smv, dstName, dstPtr, new RefGA.Multivector(0.0)); } // end of WriteSetZero()
/// <summary> /// Appends the non-mangled typenames of the type of all arguments to the name of 'F'. /// Also appends the float type. /// </summary> /// <param name="S">Specification (used for output language).</param> /// <param name="FT">Float type of function.</param> /// <param name="funcName">The function name.</param> /// <param name="typeNames">Typenames of function arguments. Some entries may be null.</param> /// <returns>new name.</returns> public static string AppendTypenameToFuncName(Specification S, G25.FloatType FT, string funcName, string[] typeNames) { StringBuilder SB = new StringBuilder(funcName); if (!funcName.Contains(G25.Specification.DONT_MANGLE)) // for the auto-dependency system to work, we should not mangle when this string is present! { foreach (string tn in typeNames) { if (tn != null) { SB.Append("_"); SB.Append(tn); } } } return(FT.GetMangledName(S, SB.ToString())); }
private static string GetZeroCodePrefix(G25.Specification S, G25.FloatType FT) { switch (S.m_outputLanguage) { case OUTPUT_LANGUAGE.C: return(S.m_namespace + "_" + FT.type + "_"); case OUTPUT_LANGUAGE.CPP: return(S.m_namespace + "::"); case OUTPUT_LANGUAGE.CSHARP: case OUTPUT_LANGUAGE.JAVA: return(S.m_namespace + "."); default: return("GetZeroCodePrefix(): not implemented yet"); } }
} // end of WriteSetCoords() /// <summary> /// Writes a function to set an SMV struct to an array of specified coordinates, for all floating point types. /// </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> public static void WriteSetArray(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.SMV smv) { //if (smv.NbNonConstBasisBlade == 0) return; cgd.m_defSB.AppendLine(""); //string className = FT.GetMangledName(S, smv.Name); string funcName = GMV.GetSetFuncName(S); bool mustCast = false; string[] argTypename = new string[2] { G25.CG.Shared.SmvUtil.COORDINATE_ORDER_ENUM, FT.type }; string[] argName = new string[2] { "co", "A" }; System.Collections.ArrayList L = new System.Collections.ArrayList(); for (int i = 0; i < smv.NbNonConstBasisBlade; i++) { RefGA.BasisBlade B = smv.NonConstBasisBlade(i); String coordStr = argName[1] + "[" + i + "]"; L.Add(new RefGA.BasisBlade(B.bitmap, B.scale, coordStr)); } RefGA.Multivector mvValue = new RefGA.Multivector(L); G25.fgs F = new G25.fgs(funcName, funcName, "", argTypename, argName, new string[] { FT.type }, null, null, null); // null, null, null = metricName, comment, options F.InitArgumentPtrFromTypeNames(S); F.SetArgumentArr(1, true); // second argument is an array bool computeMultivectorValue = false; int NB_ARGS = 2; // enum + one array of coordinates G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(S, F, NB_ARGS, FT, null, computeMultivectorValue); string dstName = G25.CG.Shared.SmvUtil.THIS; bool dstPtr = false; bool staticFunc = false; G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd, S.m_inlineSet, staticFunc, "void", null, funcName, null, FAI, FT, mustCast, smv, dstName, dstPtr, mvValue); } // end of WriteSetArray()
/// <summary> /// Writes a function to set an SMV class to specified coordinates, for all floating point types. /// </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> public static void WriteSetCoords(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.SMV smv) { //if (smv.NbNonConstBasisBlade == 0) return; cgd.m_defSB.AppendLine(""); //string className = FT.GetMangledName(S, smv.Name); string funcName = GMV.GetSetFuncName(S); bool mustCast = false; System.Collections.ArrayList L = new System.Collections.ArrayList(); int NB_ARGS = 1 + smv.NbNonConstBasisBlade; string[] argTypename = new String[NB_ARGS]; string[] argName = new String[NB_ARGS]; argTypename[0] = G25.CG.Shared.SmvUtil.COORDINATE_ORDER_ENUM; argName[0] = "co"; for (int i = 0; i < smv.NbNonConstBasisBlade; i++) { RefGA.BasisBlade B = smv.NonConstBasisBlade(i); argTypename[i + 1] = FT.type; string coordStr = "_" + smv.GetCoordLangID(i, S, COORD_STORAGE.VARIABLES); argName[i + 1] = coordStr; L.Add(new RefGA.BasisBlade(B.bitmap, B.scale, coordStr)); } RefGA.Multivector mvValue = new RefGA.Multivector(L); G25.fgs F = new G25.fgs(funcName, funcName, "", argTypename, argName, new String[] { FT.type }, null, null, null); // null, null, null = metricName, comment, options F.InitArgumentPtrFromTypeNames(S); bool computeMultivectorValue = false; G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(S, F, NB_ARGS, FT, null, computeMultivectorValue); string dstName = G25.CG.Shared.SmvUtil.THIS; bool dstPtr = false; bool staticFunc = false; G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd, S.m_inlineSet, staticFunc, "void", null, funcName, null, FAI, FT, mustCast, smv, dstName, dstPtr, mvValue); } // end of WriteSetCoords()
} // 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)); } } }
/// <summary> /// Appends the non-mangled typenames of the type of all arguments to the <c>m_outputName</c> in <c>F</c>. /// Also appends the float type. /// </summary> /// <param name="S">Specification (used for output language).</param> /// <param name="FT">Float type of function.</param> /// <param name="F">The function (it is copied, but with changed name).</param> /// <param name="FAI">Info on function arguments.</param> /// <returns>a copy of <c>F</c> with a new name.</returns> public static G25.fgs AppendTypenameToFuncName(Specification S, G25.FloatType FT, G25.fgs F, G25.CG.Shared.FuncArgInfo[] FAI) { if (S.m_outputLanguage != OUTPUT_LANGUAGE.C) { return(new G25.fgs(F, F.OutputName)); } else { string[] typeNames = new string[FAI.Length]; for (int i = 0; i < FAI.Length; i++) { if (DontAppendTypename(FAI[i].TypeName)) { continue; } typeNames[i] = FAI[i].MangledTypeName; } return(new G25.fgs(F, AppendTypenameToFuncName(S, FT, F.OutputName, typeNames))); } }
} // end of WriteDeclaration() /// <summary> /// Writes generic function based on Instructions. /// /// This version automatically figures out the return type (so it is recommended over the other WriteFunction()). /// </summary> /// <param name="S">Specification of algebra.</param> /// <param name="cgd">Results go into cgd.m_defSB, and so on</param> /// <param name="F">Function specification.</param> /// <param name="inline">When true, the code is inlined.</param> /// <param name="staticFunc">static function?</param> /// <param name="functionName">Name of generated function.</param> /// <param name="arguments">Arguments of function (any 'return argument' used for the C language is automatically setup correctly).</param> /// <param name="instructions">List of GA-instructions which make up the function.</param> /// <param name="comment">Comment to go into generated declration code.</param> public static void WriteFunction( Specification S, G25.CG.Shared.CGdata cgd, G25.fgs F, bool inline, bool staticFunc, string functionName, FuncArgInfo[] arguments, List <Instruction> instructions, Comment comment) { List <G25.VariableType> returnTypes = new List <G25.VariableType>(); List <G25.FloatType> returnTypeFT = new List <G25.FloatType>(); // floating point types of return types Instruction.GetReturnType(instructions, returnTypes, returnTypeFT); // for now, assume only one return type is used? string returnType = "void"; G25.CG.Shared.FuncArgInfo returnArgument = null; if (returnTypes.Count > 0) { G25.VariableType returnVT = returnTypes[0]; G25.FloatType returnFT = returnTypeFT[0]; if (returnVT is G25.FloatType) { returnVT = returnFT; } string returnTypeName = (returnVT is G25.MV) ? (returnVT as G25.MV).Name : (returnVT as FloatType).type; returnType = returnFT.GetMangledName(S, returnTypeName); if (S.OutputC()) { if (!(returnVT is G25.FloatType)) { returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, returnFT, returnTypeName, false); // false = compute value } } } WriteFunction(S, cgd, F, inline, staticFunc, returnType, functionName, returnArgument, arguments, instructions, comment); } // end of WriteFunction()
} // end of WriteSetZero() /// <summary> /// Writes a function to set an SMV struct to a scalar coordinate, for all floating point types which have a non-constant scalar coordinate. /// </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> public static void WriteSetScalar(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.SMV smv) { //if (smv.GetElementIdx(RefGA.BasisBlade.ONE) < 0) return; // if no scalar coordinate, continue cgd.m_defSB.AppendLine(""); //string className = FT.GetMangledName(S, smv.Name); string funcName = GMV.GetSetFuncName(S); bool mustCast = false; System.Collections.ArrayList L = new System.Collections.ArrayList(); const int NB_COORDS = 1; string[] argTypename = new String[NB_COORDS]; string[] argName = new String[NB_COORDS]; { RefGA.BasisBlade B = RefGA.BasisBlade.ONE; argTypename[0] = FT.type; argName[0] = "scalarVal"; L.Add(new RefGA.BasisBlade(B.bitmap, B.scale, argName[0])); } RefGA.Multivector mvValue = new RefGA.Multivector(L); G25.fgs F = new G25.fgs(funcName, funcName, "", argTypename, argName, new String[] { FT.type }, null, null, null); // null, null = metricName, comment, options F.InitArgumentPtrFromTypeNames(S); bool computeMultivectorValue = false; G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(S, F, NB_COORDS, FT, null, computeMultivectorValue); string dstName = G25.CG.Shared.SmvUtil.THIS; bool dstPtr = false; bool staticFunc = false; G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd, S.m_inlineSet, staticFunc, "void", null, funcName, null, FAI, FT, mustCast, smv, dstName, dstPtr, mvValue); }
/// <summary> /// Instruction for generating code for an assignment to or a return of a variable. /// /// This version of the constructor allows for a 'post operation' to be applied to the 'value'. /// Because Gaigen 2.5 cannot (yet) find common subexpressions, it is hard to generate code like /// <code> /// A.c[0] = (expr) / n2; /// A.c[1] = (expr) / n2; /// etc /// </code> /// because the division will distribute to all terms of expr. So instead you'd get: /// <code> /// A.c[0] = (expr1 / n2) + (expr2 / n2) + ... + (exprn / n2); /// A.c[1] = (expr1 / n2) + (expr2 / n2) + ... + (exprn / n2); /// etc /// </code> /// So this hack allows one to specify a post /// operator (currently multiplier (<c>"*"</c>) or divisor (<c>"/"</c>) and a value to use for that purpose. /// </summary> /// <param name="nbTabs">How many tabs to put in front of code.</param> /// <param name="T">Type of assigned variable.</param> /// <param name="FT">Floating point type of coordinates of assigned variable.</param> /// <param name="mustCast">When assigning to variable, should the coordinates be cast to FT?</param> /// <param name="value">The assigned value.</param> /// <param name="postOp">'post operation'. Currently allows for global multiplier (<c>"*"</c>) or divisor (<c>"/"</c>).</param> /// <param name="postOpValue">Value to use with 'post operation' (currently must be scalar).</param> public AssignOrReturnInstruction(int nbTabs, G25.VariableType T, G25.FloatType FT, bool mustCast, RefGA.Multivector value, string postOp, RefGA.Multivector postOpValue) : base(nbTabs) { m_type = T; m_floatType = FT; m_mustCast = mustCast; m_value = value; m_postOp = postOp; m_postOpValue = postOpValue; }
} // end of GetAssignmentStrings() /// <summary> /// Used internally by ScalarToLangString(). /// /// Emits on term (+ ....) of a blade value. Contains some optimizations /// to avoid stuff like <c>+-1.0</c>. /// </summary> protected static int EmitTerm(G25.Specification S, G25.FloatType FT, Object[] T, int tCnt, StringBuilder symResult) { // make stuff below a function bool plusEmitted = false; int pCnt = 0; // number of non-null terms in 'T' for (int p = 0; p < T.Length; p++) // for each product ...* { if (T[p] != null) { if ((!plusEmitted) && (tCnt > 0)) { symResult.Append("+"); plusEmitted = true; } if ((pCnt > 0) && (symResult.Length > 0) && (!((symResult[symResult.Length - 1] == '-') || (symResult[symResult.Length - 1] == '+')))) { symResult.Append("*"); } System.Object O = T[p]; if ((O is System.Double) || (O is System.Single) || (O is System.Int16) || (O is System.Int32) || (O is System.Int64)) // etc . . . (all number types) { double val = (double)O; if ((val == -1.0) && (p == 0) && (T.Length > 1)) { // when multiplying with -1.0, output only a '-', IF the term is the first (p==0) and more terms follow (T.Length > 1) if (symResult.Length > 0) { // when val = -1, output code which is better for humans, instead of -1.0 * ... if (symResult[symResult.Length - 1] == '+') // change '+' to '-' { symResult[symResult.Length - 1] = '-'; } else { symResult.Append("-"); } } else { symResult.Append("-"); } } else if ((val == 1.0) && (p == 0) && (T.Length > 1)) { // when multiplying with 1.0, output nothing IF the term is the first (p==0) and more terms follow (T.Length > 1) // do nothing } else { symResult.Append(FT.DoubleToString(S, (double)O)); } } else if (O is UnaryScalarOp) { UnaryScalarOp USO = (UnaryScalarOp)O; symResult.Append(UnaryScalarOpToLangString(S, FT, USO)); } else if (O is BinaryScalarOp) { BinaryScalarOp BSO = (BinaryScalarOp)O; symResult.Append(BinaryScalarOpToLangString(S, FT, BSO)); } else if (O is RefGA.BasisBlade) { symResult.Append(ScalarToLangString(S, FT, (RefGA.BasisBlade)O)); } else if (O is RefGA.Multivector) { RefGA.Multivector mv = (RefGA.Multivector)O; StringBuilder mvSB = new StringBuilder(); mvSB.Append("("); bool first = true; foreach (RefGA.BasisBlade B in mv.BasisBlades) { if (!first) { mvSB.Append(" + "); } first = false; mvSB.Append(ScalarToLangString(S, FT, B)); } mvSB.Append(")"); symResult.Append(mvSB); } else { symResult.Append(O.ToString()); } pCnt++; } } return(pCnt); }
private static string GetComment(Specification S, bool declOnly, G25.fgs FGS, G25.Operator op, G25.FloatType FT, bool assign) { StringBuilder SB = new StringBuilder(); if ((S.OutputCpp()) && op.IsUnaryInPlace()) { if (op.IsPrefix) { SB.Append("returns (" + FGS.ArgumentVariableNames[0] + " = " + FGS.OutputName + "(" + FGS.ArgumentVariableNames[0] + "))"); } else { SB.Append("returns input value of " + FGS.ArgumentVariableNames[0] + ", but sets " + FGS.ArgumentVariableNames[0] + " to " + FGS.OutputName + "(" + FGS.ArgumentVariableNames[0] + ")"); } } else if (assign) { SB.Append("returns (" + FGS.ArgumentVariableNames[0] + " = " + FGS.OutputName + "(" + FGS.ArgumentVariableNames[0]); SB.Append(", " + FGS.ArgumentVariableNames[1]); SB.Append("))"); } else { SB.Append("returns " + FGS.OutputName + "(" + FGS.ArgumentVariableNames[0]); if (op.IsBinary()) { SB.Append(", " + FGS.ArgumentVariableNames[1]); } SB.Append(")"); } return(SB.ToString()); }
/// <summary> /// Converts a scalar basis blade (with optional symbolic part) to a string in the output language of <c>S</c>. /// /// Some effort is made to output code which is close to that a human would write. /// </summary> /// <param name="S">Specification of algebra, used for output language, basis vector names, etc.</param> /// <param name="FT">Floating point type of output.</param> /// <param name="B">The basis blade.</param> /// <returns>String code representation of 'B'.</returns> public static string ScalarToLangString(G25.Specification S, G25.FloatType FT, RefGA.BasisBlade B) { string symScaleStr = ""; { // convert symbolic part if (B.symScale != null) { // symbolic scalar string goes in symResult System.Text.StringBuilder symResult = new System.Text.StringBuilder(); int tCnt = 0; for (int t = 0; t < B.symScale.Length; t++) // for each term ...*...*...+ { Object[] T = (Object[])B.symScale[t].Clone(); // clone 'T' because IsolateInverses() might alter it! if (T != null) // if term is not null { // first find all scalarop inverses // turn those into a new term, but without inverses? Object[] TI = IsolateInverses(T); // emit 'T' int pCnt = EmitTerm(S, FT, T, tCnt, symResult); if (TI != null) // do we have to divide by a number of terms? { // emit '/(TI)' symResult.Append("/("); EmitTerm(S, FT, TI, 0, symResult); symResult.Append(")"); } if (pCnt > 0) { tCnt++; // only increment number of terms when T was not empty } } } if (tCnt > 0) { symScaleStr = ((tCnt > 1) ? "(" : "") + symResult + ((tCnt > 1) ? ")" : ""); } } } // end of symbolic part // special cases when numerical scale is exactly +- 1 if (B.scale == 1.0) { if (symScaleStr.Length > 0) { return(symScaleStr); } else { return(FT.DoubleToString(S, 1.0)); } } else if (B.scale == -1.0) { if (symScaleStr.Length > 0) { return("-" + symScaleStr); } else { return(FT.DoubleToString(S, -1.0)); } } else { // get numerical part string numScaleStr = FT.DoubleToString(S, B.scale); // merge symbolic and numerical if (symScaleStr.Length > 0) { numScaleStr = numScaleStr + "*" + symScaleStr; } // done return(numScaleStr); } } // end of function ScalarToLangString