/// <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> /// Applies 'm_postOp m_postOpValue' to 'valueStr'. /// </summary> /// <param name="S">Specification of algebra.</param> /// <param name="cgd">Not used yet.</param> /// <param name="valueStr">The array of value strings to which the postop should be applied</param> /// <param name="BL">Not used yet. May be used later on to known what basis blade each valueStr refers to.</param> public void ApplyPostOp(Specification S, G25.CG.Shared.CGdata cgd, RefGA.BasisBlade[] BL, String[] valueStr) { if (m_postOp == null) { return; } // TODO: currently only for *= and /= // get string of value: string postOpValueStr; RefGA.Multivector sc = m_postOpValue.ScalarPart(); if (sc.IsZero()) { postOpValueStr = CodeUtil.ScalarToLangString(S, m_floatType, RefGA.BasisBlade.ZERO); } else { postOpValueStr = CodeUtil.ScalarToLangString(S, m_floatType, sc.BasisBlades[0]); } // apply "m_postOp postOpValueStr" to all valueStr for (int i = 0; i < valueStr.Length; i++) { valueStr[i] = "(" + valueStr[i] + ")" + m_postOp + ((m_mustCast) ? m_floatType.castStr : "") + "(" + postOpValueStr + ")"; } }
} // end of WriteSetCopy() /// <summary> /// Writes a function to copy the value of one SMV struct to another with a different floating point type, for all combinations of 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 WriteSetCopyCrossFloat(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType dstFT, G25.SMV smv) { foreach (G25.FloatType srcFT in S.m_floatTypes) { if (srcFT.type == dstFT.type) { continue; } cgd.m_defSB.AppendLine(""); //string srcClassName = srcFT.GetMangledName(smv.Name); //string dstClassName = dstFT.GetMangledName(S, smv.Name); string funcName = GMV.GetSetFuncName(S); bool mustCast = dstFT.MustCastIfAssigned(S, srcFT); G25.fgs F = new G25.fgs(funcName, funcName, "", new String[] { smv.Name }, null, new String[] { srcFT.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, srcFT, 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, dstFT, mustCast, smv, dstName, dstPtr, value); } } // end of WriteSetCopyCrossFloat()
} // 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 WriteCopy(Specification S, G25.CG.Shared.CGdata cgd) { //StringBuilder declSB = cgd.m_declSB; StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; defSB.AppendLine(""); foreach (G25.FloatType FT in S.m_floatTypes) { foreach (G25.SMV smv in S.m_SMV) { // if (smv.NbNonConstBasisBlade == 0) continue; string className = FT.GetMangledName(S, smv.Name); string funcName = className + "::set"; 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 = true; 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 WriteCopy()
/// <summary> /// Takes a general multivector specification (G25.GMV) and converts it into a one symbolic multivector per group/grade part. /// /// The symbolic weights of the multivector are the coordinates of the GMV, labelled according to 'gmvName'. /// Currently, the indices start at zero for each group. /// </summary> /// <param name="S">Specification of the algebra. Used for the access convention (. or ->) and for how to name the coordinates ([0] or e1, e2, e3).</param> /// <param name="gmv">The specification of the general multivector.</param> /// <param name="gmvName">Name the variable should have.</param> /// <param name="ptr">Is 'gmvName' a pointer? (not used currently)</param> /// <param name="groupIdx">Index of group/grade to convert (use -1 for all groups)</param> /// <returns></returns> public static RefGA.Multivector[] GMVtoSymbolicMultivector(Specification S, G25.GMV gmv, String gmvName, bool ptr, int groupIdx) { RefGA.Multivector[] R = new RefGA.Multivector[gmv.NbGroups]; //String accessStr = (ptr) ? "->" : "."; for (int g = 0; g < gmv.NbGroups; g++) { if ((groupIdx >= 0) && (g != groupIdx)) { continue; // only one group requested? } RefGA.BasisBlade[] B = gmv.Group(g); RefGA.BasisBlade[] L = new RefGA.BasisBlade[B.Length]; for (int i = 0; i < B.Length; i++) { RefGA.BasisBlade b = B[i]; String fullCoordName = gmvName + "[" + i + "]"; // merge L[i] = new RefGA.BasisBlade(b.bitmap, b.scale, fullCoordName); } R[g] = new RefGA.Multivector(L); } return(R); } // end of function GMVtoSymbolicMultivector()
/// <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; }
} // end of WriteSet() /// <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) { StringBuilder declSB = cgd.m_declSB; StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; declSB.AppendLine(""); defSB.AppendLine(""); foreach (G25.FloatType FT in S.m_floatTypes) { foreach (G25.SMV smv in S.m_SMV) { if (smv.NbNonConstBasisBlade == 0) { continue; } string typeName = FT.GetMangledName(S, smv.Name); string funcName = typeName + "_setArray"; bool mustCast = false; string[] argTypename = new string[1] { FT.type }; string[] argName = new string[1] { "A" }; System.Collections.ArrayList L = new System.Collections.ArrayList(); for (int i = 0; i < smv.NbNonConstBasisBlade; i++) { RefGA.BasisBlade B = smv.NonConstBasisBlade(i); //argTypename[i] = FT.type; String coordStr = argName[0] + "[" + i + "]"; //argName[i] = 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); F.SetArgumentPtr(0, true); // first argument is a pointer to array bool computeMultivectorValue = false; G25.CG.Shared.FuncArgInfo returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, FT, smv.Name, computeMultivectorValue); int nbArgs = 1; // one array of coordinates G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(S, F, nbArgs, FT, null, computeMultivectorValue); declSB.AppendLine("/** Sets " + typeName + " to specified coordinates */"); bool staticFunc = false; G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd, S.m_inlineSet, staticFunc, "void", null, funcName, returnArgument, FAI, FT, mustCast, smv, returnArgument.Name, returnArgument.Pointer, mvValue); } } } // end of WriteSetArray()
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { m_ipType = GetIpType(m_specification, m_fgs); // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) { m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name, m_gmv.Name } } ; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !(tmpFAI[0].IsScalarOrSMV() && tmpFAI[1].IsScalarOrSMV()); m_smv1 = tmpFAI[0].Type as G25.SMV; m_smv2 = tmpFAI[1].Type as G25.SMV; // compute intermediate results, set return type if (m_gmvFunc) { if (m_ipType != RefGA.BasisBlade.InnerProductType.SCALAR_PRODUCT) { m_fgs.m_returnTypeName = m_gmv.Name;// gmv * gmv = gmv } else { m_fgs.ReturnTypeName = FT.type; } } else { // compute return value m_returnValue = RefGA.Multivector.ip(tmpFAI[0].MultivectorValue[0], tmpFAI[1].MultivectorValue[0], m_M, m_ipType); // round value if required by metric if (m_G25M.m_round) { m_returnValue = m_returnValue.Round(1e-14); } // get name of return type if ((m_fgs.ReturnTypeName.Length == 0) && (m_ipType != RefGA.BasisBlade.InnerProductType.SCALAR_PRODUCT)) { m_fgs.ReturnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } else { m_fgs.ReturnTypeName = FT.type; } } }
public static void WriteSetCopy(Specification S, G25.CG.Shared.CGdata cgd, FloatType FT, G25.SOM som) { StringBuilder declSB = cgd.m_declSB; StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; if (S.OutputC()) { declSB.AppendLine(); } defSB.AppendLine(); string typeName = FT.GetMangledName(S, som.Name); string funcName = GetFunctionName(S, typeName, "set", "_set"); bool mustCast = false; const int NB_ARGS = 1; string srcName = "src"; bool srcPtr = S.OutputC(); G25.fgs F = new G25.fgs(funcName, funcName, "", new String[] { som.Name }, new String[] { srcName }, 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_ARGS, FT, S.m_GMV.Name, computeMultivectorValue); G25.CG.Shared.FuncArgInfo returnArgument = null; if (S.OutputC()) { returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, FT, som.Name, computeMultivectorValue); } // setup instructions List <G25.CG.Shared.Instruction> I = new List <G25.CG.Shared.Instruction>(); { int nbTabs = 1; mustCast = false; string dstName = (S.OutputC()) ? G25.fgs.RETURN_ARG_NAME : SmvUtil.THIS; bool dstPtr = (S.OutputCppOrC()); bool declareDst = false; for (int g = 1; g < som.Domain.Length; g++) { for (int c = 0; c < som.DomainForGrade(g).Length; c++) { G25.SMVOM smvOM = som.DomainSmvForGrade(g)[c]; RefGA.Multivector srcValue = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(S, smvOM, srcName, srcPtr); I.Add(new G25.CG.Shared.AssignInstruction(nbTabs, smvOM, FT, mustCast, srcValue, dstName, dstPtr, declareDst)); } } } Comment comment = new Comment("Copies " + typeName + ".");; bool writeDecl = (S.OutputC()); bool staticFunc = false; G25.CG.Shared.Functions.WriteFunction(S, cgd, F, S.m_inlineSet, staticFunc, "void", funcName, returnArgument, FAI, I, comment, writeDecl); }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) { m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name, m_gmv.Name } } ; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !(tmpFAI[0].IsScalarOrSMV() && tmpFAI[1].IsScalarOrSMV()); m_trueGmvFunc = (!tmpFAI[0].IsScalarOrSMV()) && (!tmpFAI[1].IsScalarOrSMV()); m_arg1isGmv = !tmpFAI[0].IsScalarOrSMV(); m_arg2isGmv = !tmpFAI[1].IsScalarOrSMV(); m_smv1 = tmpFAI[0].Type as G25.SMV; m_smv2 = tmpFAI[1].Type as G25.SMV; // compute intermediate results, set return type if (m_gmvFunc) { m_fgs.m_returnTypeName = m_gmv.Name; // gmv * gmv = gmv } else { // compute return value m_reverseValue = RefGA.Multivector.Reverse(tmpFAI[1].MultivectorValue[0]); m_n2Value = RefGA.Multivector.gp(m_reverseValue, tmpFAI[1].MultivectorValue[0], m_M); if (m_G25M.m_round) { m_n2Value = m_n2Value.Round(1e-14); } //m_returnValue = RefGA.Multivector.gp(RefGA.Multivector.gp(tmpFAI[0].MultivectorValue[0], m_reverseValue, m_M), // RefGA.Symbolic.ScalarOp.Inverse(new RefGA.Multivector(new RefGA.BasisBlade(0, 1.0, m_normSquaredName)))); m_returnValue = RefGA.Multivector.gp(tmpFAI[0].MultivectorValue[0], m_reverseValue, m_M); // round value if required by metric if (m_G25M.m_round) { m_returnValue = m_returnValue.Round(1e-14); } // get name of return type if (m_fgs.m_returnTypeName.Length == 0) { m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } } }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { if (m_G25M.m_metric.IsDegenerate()) { throw new G25.UserException("Cannot generate dual functions for degenerate metrics."); } // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) { m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name } } ; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !tmpFAI[0].IsScalarOrSMV(); // compute intermediate results, set return type if (m_gmvFunc) { m_fgs.m_returnTypeName = m_gmv.Name; // dual(gmv) = gmv } else { m_smv = tmpFAI[0].Type as G25.SMV; // compute return value if (IsDual(m_fgs)) { m_returnValue = RefGA.Multivector.Dual(tmpFAI[0].MultivectorValue[0], m_M); } else if (IsUndual(m_fgs)) { m_returnValue = RefGA.Multivector.Undual(tmpFAI[0].MultivectorValue[0], m_M); } // round value if required by metric if (m_G25M.m_round) { m_returnValue = m_returnValue.Round(1e-14); } // get name of return type if (m_fgs.m_returnTypeName.Length == 0) { m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } } }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) { m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name } } ; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !tmpFAI[0].IsScalarOrSMV(); m_isNorm2 = IsNorm2(m_fgs); // compute intermediate results, set return type if (m_gmvFunc) { m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, new RefGA.Multivector("x")).GetName(); // norm(gmv) = scalar } else { m_smv = tmpFAI[0].Type as G25.SMV; // compute return value if (m_isNorm2) { m_returnValue = tmpFAI[0].MultivectorValue[0].Norm_r2(m_M); } else { m_returnValue = RefGA.Symbolic.UnaryScalarOp.Abs(tmpFAI[0].MultivectorValue[0].Norm_r(m_M)); } // round value if required by metric if (m_G25M.m_round) { m_returnValue = m_returnValue.Round(1e-14); } // avoid null return value because that might return in getting the wrong return type RefGA.Multivector nonZeroReturnValue = (m_returnValue.IsZero()) ? RefGA.Multivector.ONE : m_returnValue; // get name of return type if (m_fgs.m_returnTypeName.Length == 0) { m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, nonZeroReturnValue).GetName(); } } }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) { m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name } } ; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !tmpFAI[0].IsScalarOrSMV(); // compute intermediate results, set return type if (m_gmvFunc) { m_fgs.m_returnTypeName = m_gmv.Name; // dual(gmv) = gmv } else { m_smv = tmpFAI[0].Type as G25.SMV; // get symbolic result m_reverseValue = RefGA.Multivector.Reverse(tmpFAI[0].MultivectorValue[0]); m_n2Value = RefGA.Multivector.gp(m_reverseValue, tmpFAI[0].MultivectorValue[0], m_M); if (m_G25M.m_round) { m_n2Value = m_n2Value.Round(1e-14); } if (m_n2Value.HasSymbolicScalars() || (!m_n2Value.IsScalar()) || m_n2Value.IsZero()) { m_inverseValue = RefGA.Multivector.gp(m_reverseValue, RefGA.Symbolic.UnaryScalarOp.Inverse(new RefGA.Multivector(new RefGA.BasisBlade(0, 1.0, m_normSquaredName)))); } else { m_inverseValue = RefGA.Multivector.gp(m_reverseValue, new RefGA.Multivector(1.0 / m_n2Value.RealScalarPart())); m_n2Value = null; } // get name of return type if (m_fgs.m_returnTypeName.Length == 0) { m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_inverseValue).GetName(); } } m_returnType = m_specification.GetType(m_fgs.m_returnTypeName); }
/// <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> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) { m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name } } ; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !tmpFAI[0].IsScalarOrSMV(); // compute intermediate results, set return type if (m_gmvFunc) { m_fgs.m_returnTypeName = m_gmv.Name; // toggle_sign(gmv) = gmv } else { m_smv = tmpFAI[0].Type as G25.SMV; // compute return value if (IsNegate(m_fgs)) { m_returnValue = RefGA.Multivector.Negate(tmpFAI[0].MultivectorValue[0]); } else if (IsReverse(m_fgs)) { m_returnValue = RefGA.Multivector.Reverse(tmpFAI[0].MultivectorValue[0]); } else if (IsCliffordConjugate(m_fgs)) { m_returnValue = RefGA.Multivector.CliffordConjugate(tmpFAI[0].MultivectorValue[0]); } else if (IsGradeInvolution(m_fgs)) { m_returnValue = RefGA.Multivector.GradeInvolution(tmpFAI[0].MultivectorValue[0]); } // get name of return type if (m_fgs.m_returnTypeName.Length == 0) { m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } } }
} // end of WriteSet() /// <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) { StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; defSB.AppendLine(""); foreach (G25.FloatType FT in S.m_floatTypes) { foreach (G25.SMV smv in S.m_SMV) { if (smv.NbNonConstBasisBlade == 0) { continue; } string className = FT.GetMangledName(S, smv.Name); string funcName = className + "::set"; 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.SetArgumentPtr(1, true); // second argument is a pointer to 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 = true; 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 struct 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) { StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; defSB.AppendLine(""); foreach (G25.FloatType FT in S.m_floatTypes) { foreach (G25.SMV smv in S.m_SMV) { if (smv.NbNonConstBasisBlade == 0) { continue; } string className = FT.GetMangledName(S, smv.Name); string funcName = className + "::set"; 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 returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, FT, smv.Name, computeMultivectorValue); 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 = true; 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 WriteSet()
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// - Optionally fill in F.m_argumentPtr /// </summary> public override void CompleteFGS() { // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) { m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name, m_gmv.Name } } ; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !(tmpFAI[0].IsScalarOrSMV() && tmpFAI[1].IsScalarOrSMV()); m_trueGmvFunc = (!tmpFAI[0].IsScalarOrSMV()) && (!tmpFAI[1].IsScalarOrSMV()); m_smv1 = tmpFAI[0].Type as G25.SMV; m_smv2 = tmpFAI[1].Type as G25.SMV; // compute intermediate results, set return type if (m_gmvFunc) { m_fgs.m_returnTypeName = m_gmv.Name; // gmv + gmv = gmv } else { // compute return value if (IsAdd(m_fgs)) { m_returnValue = RefGA.Multivector.Add(tmpFAI[0].MultivectorValue[0], tmpFAI[1].MultivectorValue[0]); } else if (IsSubtract(m_fgs)) { m_returnValue = RefGA.Multivector.Subtract(tmpFAI[0].MultivectorValue[0], tmpFAI[1].MultivectorValue[0]); } // get name of return type if (m_fgs.m_returnTypeName.Length == 0) { m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } } }
} // 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) { StringBuilder declSB = cgd.m_declSB; StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; declSB.AppendLine(""); defSB.AppendLine(""); foreach (G25.FloatType FT in S.m_floatTypes) { foreach (G25.SMV smv in S.m_SMV) { // if (smv.NbNonConstBasisBlade == 0) continue; if (smv.GetElementIdx(RefGA.BasisBlade.ONE) < 0) { continue; // if no scalar coordinate, continue } string typeName = FT.GetMangledName(S, smv.Name); string funcName = typeName + "_setScalar"; 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 returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, FT, smv.Name, computeMultivectorValue); G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(S, F, NB_COORDS, FT, null, computeMultivectorValue); declSB.AppendLine("/** Sets " + typeName + " to a scalar value */"); bool staticFunc = false; G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd, S.m_inlineSet, staticFunc, "void", null, funcName, returnArgument, FAI, FT, mustCast, smv, returnArgument.Name, returnArgument.Pointer, mvValue); } } }
} // end of WriteCopy() /// <summary> /// Writes a function to copy the value of one SMV struct to another with a different floating point type, for all combinations of 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 WriteCopyCrossFloat(Specification S, G25.CG.Shared.CGdata cgd) { StringBuilder declSB = cgd.m_declSB; StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; declSB.AppendLine(""); defSB.AppendLine(""); foreach (G25.FloatType srcFT in S.m_floatTypes) { foreach (G25.FloatType dstFT in S.m_floatTypes) { if (srcFT.type == dstFT.type) { continue; } foreach (G25.SMV smv in S.m_SMV) { if (smv.NbNonConstBasisBlade == 0) { continue; } String srcTypeName = srcFT.GetMangledName(S, smv.Name); String dstTypeName = dstFT.GetMangledName(S, smv.Name); G25.fgs tmpFgs = null; String funcName = G25.CG.Shared.Converter.GetConverterName(S, tmpFgs, srcTypeName, dstTypeName); bool mustCast = dstFT.MustCastIfAssigned(S, srcFT); G25.fgs F = new G25.fgs(funcName, funcName, "", new String[] { smv.Name }, null, new String[] { srcFT.type }, null, null, null); // null, null, null = metricName, comment, options F.InitArgumentPtrFromTypeNames(S); bool computeMultivectorValue = false; G25.CG.Shared.FuncArgInfo returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, dstFT, smv.Name, computeMultivectorValue); int nbArgs = 1; G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(S, F, nbArgs, srcFT, null, computeMultivectorValue); declSB.AppendLine("/** Copies " + srcTypeName + " to " + dstTypeName + ": " + returnArgument.Name + " = " + FAI[0].Name + " */"); RefGA.Multivector value = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(S, smv, FAI[0].Name, FAI[0].Pointer); bool staticFunc = false; G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd, S.m_inlineSet, staticFunc, "void", null, funcName, returnArgument, FAI, dstFT, mustCast, smv, returnArgument.Name, returnArgument.Pointer, value); } } } } // end of WriteCopyCrossFloat()
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { m_gradeIdx = GetGradeIdx(m_fgs.Name); // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) { m_fgs.m_argumentTypeNames = new string[] { m_gmv.Name } } ; // supplement the extra 'int' argument if ((m_gradeIdx < 0) && (m_fgs.ArgumentTypeNames.Length == 1)) { m_fgs.m_argumentTypeNames = new string[] { m_fgs.ArgumentTypeNames[0], G25.GroupBitmapType.GROUP_BITMAP }; m_fgs.m_argumentVariableNames = new string[] { m_fgs.m_argumentVariableNames[0], "groupBitmap" }; } // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !tmpFAI[0].IsScalarOrSMV(); m_smv = tmpFAI[0].Type as G25.SMV; // compute intermediate results, set return type if (m_gmvFunc) { m_fgs.m_returnTypeName = m_gmv.Name; // grade(gmv) = gmv } else { // compute return value m_returnValue = tmpFAI[0].MultivectorValue[0].ExtractGrade(m_gradeIdx); // get name of return type if (m_fgs.m_returnTypeName.Length == 0) { m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } } }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// /// As the return type is required, many functions will also compute the return value and other info /// needed for generating the code inside this function. These intermediate values are then /// stored in class variables so they can be reused in WriteFunction() /// </summary> public override void CompleteFGS() { NB_ARGS = m_fgs.NbArguments; // all arguments must be explicitly listed // in C language, all arguments are pointers if (m_fgs.ArgumentPtr.Length == 0) { bool ptr = m_specification.OutputC(); m_fgs.m_argumentPtr = new bool[] { ptr, ptr }; m_fgs.m_argumentArr = new bool[] { false, false }; } // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_smv1 = tmpFAI[0].Type as G25.SMV; m_smv2 = tmpFAI[1].Type as G25.SMV; { // compute return value // compute symbolic distance squared value m_returnValue = RefGA.Multivector.gp( RefGA.Multivector.ScalarProduct(tmpFAI[0].MultivectorValue[0], tmpFAI[1].MultivectorValue[0], m_M), -2.0); // apply sqrt(fabs()) if distance should not be squared: if (IsDistance(m_fgs)) { m_returnValue = RefGA.Symbolic.UnaryScalarOp.Sqrt(RefGA.Symbolic.UnaryScalarOp.Abs(m_returnValue)); } // round value if required by metric if (m_G25M.m_round) { m_returnValue = m_returnValue.Round(1e-14); } } // get name of return type if (m_fgs.m_returnTypeName.Length == 0) { m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } } // end of CompleteFGS()
/// <summary> /// Converts a symbolic multivector value to a textual description of the specialized multivector /// type that would be required to store that value. This is used for presenting error messages /// to users when a suitable specialized type cannot be found for a specific multivector value. /// </summary> /// <param name="S">Specification, used for basis vector names.</param> /// <param name="value">The value to describe.</param> /// <returns>Textual description of the type that can store 'value'.</returns> public static String MultivectorToTypeDescription(G25.Specification S, RefGA.Multivector value) { StringBuilder SB = new StringBuilder(); bool appendSpace = false; foreach (RefGA.BasisBlade B in value.BasisBlades) { if (appendSpace) SB.Append(" "); SB.Append(new RefGA.BasisBlade(B.bitmap).ToString(S.m_basisVectorNames)); if (B.symScale == null) SB.Append("=" + B.scale); appendSpace = true; } return SB.ToString(); }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) { m_fgs.m_argumentTypeNames = new string[] { m_gmv.Name } } ; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !tmpFAI[0].IsScalarOrSMV(); // compute intermediate results, set return type if (m_gmvFunc) { m_fgs.m_returnTypeName = m_gmv.Name; // unit(gmv) = gmv } else { m_smv = tmpFAI[0].Type as G25.SMV; // get symbolic result m_grade0Value = tmpFAI[0].MultivectorValue[0].ExtractGrade(0); m_grade2Value = tmpFAI[0].MultivectorValue[0].ExtractGrade(2); RefGA.Multivector reverseGrade2Value = RefGA.Multivector.Reverse(m_grade2Value); m_grade2norm2Value = RefGA.Multivector.gp(reverseGrade2Value, m_grade2Value, m_M); m_returnValue = RefGA.Multivector.gp(m_grade2Value, new RefGA.Multivector(mulName)); // where mulName = atan2(sqrt(grade2norm2), grade0) / sqrt(grade2norm2) // get name of return type if (m_fgs.m_returnTypeName.Length == 0) { m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } } m_returnType = m_specification.GetType(m_fgs.m_returnTypeName); }
} // end of WriteAssignmentFunction() /// <summary> /// /// </summary> /// <param name="S">Used for all kinds of stuff.</param> /// <param name="cgd">Results go into cgd.m_defSB, and so on</param> /// <param name="inline">Should the function we inline?</param> /// <param name="staticFunc">Static function?</param> /// <param name="functionName">The name of the function which is to be generated.</param> /// <param name="arguments">Array of FuncArg which describes the arguments of the function.</param> /// <param name="returnFT">Floating point type of return variable.</param> /// <param name="mustCastDst">set to true if coordinates of 'value' must be cast to 'dstFT'.</param> /// <param name="returnType">The type to be returned.</param> /// <param name="value">Value to be written to the returned.</param> public static void WriteReturnFunction( Specification S, G25.CG.Shared.CGdata cgd, bool inline, bool staticFunc, string functionName, FuncArgInfo[] arguments, FloatType returnFT, bool mustCastDst, G25.VariableType returnType, RefGA.Multivector value) { string returnTypeName; bool returnSMV = returnType is G25.SMV; if (returnSMV) { returnTypeName = returnFT.GetMangledName(S, (returnType as G25.SMV).Name); } else { returnTypeName = (returnType as G25.FloatType).type; } // where the definition goes: StringBuilder defSB = (inline) ? cgd.m_inlineDefSB : cgd.m_defSB; // declaration: if (S.OutputCppOrC()) { WriteDeclaration(cgd.m_declSB, S, cgd, false, staticFunc, returnTypeName, functionName, null, arguments); cgd.m_declSB.AppendLine(";"); } WriteDeclaration(defSB, S, cgd, inline, staticFunc, returnTypeName, functionName, null, arguments); defSB.AppendLine(""); defSB.AppendLine("{"); int nbTabs = 1; ReturnInstruction RI = new ReturnInstruction(nbTabs, returnType, returnFT, mustCastDst, value); RI.Write(defSB, S, cgd); defSB.Append("\n"); defSB.AppendLine("}"); } // end of WriteReturnFunction()
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) { m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name, FT.type } } ; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !tmpFAI[0].IsScalarOrSMV(); // compute intermediate results, set return type if (m_gmvFunc) { m_fgs.m_returnTypeName = m_gmv.Name; // div(gmv, scalar) = gmv } else { m_smv = tmpFAI[0].Type as G25.SMV; RefGA.Multivector inputValue = tmpFAI[0].MultivectorValue[0]; RefGA.Multivector divValue = RefGA.Symbolic.UnaryScalarOp.Inverse(new RefGA.Multivector(tmpFAI[1].Name)); m_returnValue = RefGA.Multivector.gp(inputValue, divValue); // get name of return type if (m_fgs.m_returnTypeName.Length == 0) { m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } } }
/// <summary> /// Generates code to assign <c>value</c> to a variable whose coordinate order is specified by <c>BL</c>. /// /// For example, <c>BL</c> could be <c>[e1, e2, e3]</c> and the multivector value <c>[e1 - 2e3]</c>. /// Then the returned array would be <c>["1", "0", "-2"]</c>. /// /// Parts of <c>value</c> that cannot be assigned to <c>BL</c> are silently ignored. /// /// Possibly, at some point we would like to generate some kind of warning? /// </summary> /// <param name="S">Specification of algebra (not used yet).</param> /// <param name="FT">Floating point type of assigned variable (used for casting strings).</param> /// <param name="mustCast">Set to true if a cast to 'FT' must be performed.</param> /// <param name="BL">Basis blades of assigned variable.</param> /// <param name="value">Multivector value to assign to the list of basis blades. /// Must not contain basis blades inside the symbolic scalars of the RefGA.BasisBlades.</param> /// <param name="writeZeros">When true, <c>"0"</c> will be returned when no value should be assigned /// to some coordinate. <c>null</c> otherwise.</param> /// <returns>An array of strings which tell you what to assign to each coordinate.</returns> public static String[] GetAssignmentStrings(Specification S, FloatType FT, bool mustCast, RefGA.BasisBlade[] BL, RefGA.Multivector value, bool writeZeros) { String[] assignedStr = new String[BL.Length]; int idx = 0; // for each non-const coord, find out what value is (loop through all entries in value) foreach (RefGA.BasisBlade B in BL) { // find same basisblade in 'value' foreach (RefGA.BasisBlade C in value.BasisBlades) { if (C.bitmap == B.bitmap) // match found: get assignment string { // compute D = inverse(B) . C; RefGA.BasisBlade Bi = (new RefGA.BasisBlade(B.bitmap, 1.0 / B.scale)).Reverse(); RefGA.BasisBlade D = RefGA.BasisBlade.scp(Bi, C); if (mustCast) { assignedStr[idx] = FT.castStr + "(" + CodeUtil.ScalarToLangString(S, FT, D) + ")"; } else { assignedStr[idx] = CodeUtil.ScalarToLangString(S, FT, D); } break; } } if (writeZeros && (assignedStr[idx] == null)) // has an assignment string been set? { // no assignment: simply assign "0" assignedStr[idx] = FT.DoubleToString(S, 0.0); } idx++; } return(assignedStr); } // end of GetAssignmentStrings()
/// <summary> /// Takes a general multivector specification (G25.GMV) and converts it into a one symbolic multivector per group/grade part. /// /// The symbolic weights of the multivector are the coordinates of the GMV, labelled according to 'gmvName'. /// Currently, the indices start at zero for each group. /// </summary> /// <param name="S">Specification of the algebra. Used for the access convention (. or ->) and for how to name the coordinates ([0] or e1, e2, e3).</param> /// <param name="gmv">The specification of the general multivector.</param> /// <param name="gmvName">Name the variable should have.</param> /// <param name="ptr">Is 'gmvName' a pointer? (not used currently)</param> /// <param name="groupIdx">Index of group/grade to convert (use -1 for all groups)</param> /// <returns></returns> public static RefGA.Multivector[] GMVtoSymbolicMultivector(Specification S, G25.GMV gmv, String gmvName, bool ptr, int groupIdx) { RefGA.Multivector[] R = new RefGA.Multivector[gmv.NbGroups]; //String accessStr = (ptr) ? "->" : "."; for (int g = 0; g < gmv.NbGroups; g++) { if ((groupIdx >= 0) && (g != groupIdx)) continue; // only one group requested? RefGA.BasisBlade[] B = gmv.Group(g); RefGA.BasisBlade[] L = new RefGA.BasisBlade[B.Length]; for (int i = 0; i < B.Length; i++) { RefGA.BasisBlade b = B[i]; String fullCoordName = gmvName + "[" + i + "]"; // merge L[i] = new RefGA.BasisBlade(b.bitmap, b.scale, fullCoordName); } R[g] = new RefGA.Multivector(L); } return R; }
} // end of 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); }
private static void WriteConvertingConstructor(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd, FloatType FT, G25.fgs fgs, SMV srcSmv, SMV dstSmv) { string srcTypeName = FT.GetMangledName(S, srcSmv.GetName()); string dstTypeName = FT.GetMangledName(S, dstSmv.GetName()); string argName = "x"; Comment comment = new Comment("Converting constructor, from " + srcTypeName + " to " + dstTypeName); comment.Write(SB, S, 1); SB.AppendLine("\tpublic " + dstTypeName + "(" + srcTypeName + " " + argName + ") {"); int nbTabs = 2; bool declareVariable = false; bool cast = false; bool srcPtr = false; bool dstPtr = false; RefGA.Multivector value = Symbolic.SMVtoSymbolicMultivector(S, srcSmv, argName, srcPtr); AssignInstruction AI = new AssignInstruction(nbTabs, dstSmv, FT, cast, value, SmvUtil.THIS, dstPtr, declareVariable); AI.Write(SB, S, cgd); SB.AppendLine("\t}"); }
/// <summary> /// Writes a function to set an SMV struct 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 WriteSet(Specification S, G25.CG.Shared.CGdata cgd) { StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; defSB.AppendLine(""); foreach (G25.FloatType FT in S.m_floatTypes) { foreach (G25.SMV smv in S.m_SMV) { if (smv.NbNonConstBasisBlade == 0) continue; string className = FT.GetMangledName(S, smv.Name); string funcName = className + "::set"; 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 returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, FT, smv.Name, computeMultivectorValue); 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 = true; G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd, S.m_inlineSet, "void", null, funcName, null, FAI, FT, mustCast, smv, dstName, dstPtr, mvValue); } } }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name }; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !tmpFAI[0].IsScalarOrSMV(); // compute intermediate results, set return type if (m_gmvFunc) { m_fgs.m_returnTypeName = m_gmv.Name; // sin/cos/sinh/cosh/exp(gmv) = gmv m_returnType = m_gmv; m_inputTypeName = m_gmv.Name; m_returnTypeName = m_gmv.Name; } else { m_smv = tmpFAI[0].Type as G25.SMV; try // exceptions are caught below -> in that case, do a series for the SMV { // sin/cos/sinh/cosh/exp(smv bivector) RefGA.Multivector value = tmpFAI[0].MultivectorValue[0]; RefGA.Multivector squareValue = RefGA.Multivector.gp(value, value, m_M); String userSetSquare = m_fgs.GetOption("square"); if (userSetSquare != null) m_signOfSquare = (int)Math.Sign(Double.Parse(userSetSquare)); else { // the following line can throw an exception, which is caught below double sqEval = RefGA.Symbolic.SymbolicUtil.EvaluateRandomSymbolicToScalar(squareValue); m_signOfSquare = (int)Math.Sign(sqEval); } m_scalarSquare = true; // compute alpha = sqrt(fabs(value^2)) m_alphaValue = RefGA.Symbolic.UnaryScalarOp.Sqrt(RefGA.Symbolic.UnaryScalarOp.Abs(squareValue)); // use hyperbolic sin / cos or regular sin / cos for shortcuts? bool hyperbolic = (((IsExp(m_fgs) || IsCosh(m_fgs) || IsSinh(m_fgs)) && (m_signOfSquare > 0)) || ((IsCos(m_fgs) || IsSin(m_fgs)) && (m_signOfSquare < 0))); // compute mul for SIN and EXP (assuming alpha is not zero) if (IsCos(m_fgs) || m_alphaValue.IsZero()) m_mulValue = RefGA.Multivector.ONE; else if (m_signOfSquare == 0) m_mulValue = RefGA.Multivector.ZERO; else { if (hyperbolic) m_mulValue = RefGA.Multivector.gp( RefGA.Symbolic.UnaryScalarOp.Sinh(new RefGA.Multivector(m_alphaName)), RefGA.Symbolic.UnaryScalarOp.Inverse(new RefGA.Multivector(m_alphaName))); else m_mulValue = RefGA.Multivector.gp( RefGA.Symbolic.UnaryScalarOp.Sin(new RefGA.Multivector(m_alphaName)), RefGA.Symbolic.UnaryScalarOp.Inverse(new RefGA.Multivector(m_alphaName))); } // compute sin, cos part RefGA.Multivector cosValue = null, sinValue = null; if (m_signOfSquare == 0) { cosValue = RefGA.Multivector.ONE; sinValue = value; } else { sinValue = RefGA.Multivector.gp(value, new RefGA.Multivector(m_mulName)); if (hyperbolic) cosValue = RefGA.Symbolic.UnaryScalarOp.Cosh(new RefGA.Multivector(m_alphaName)); else cosValue = RefGA.Symbolic.UnaryScalarOp.Cos(new RefGA.Multivector(m_alphaName)); } // compute return value if (IsExp(m_fgs)) m_returnValue = RefGA.Multivector.Add(cosValue, sinValue); else if (IsCos(m_fgs) || IsCosh(m_fgs)) m_returnValue = cosValue; else if (IsSin(m_fgs) || IsSinh(m_fgs)) m_returnValue = sinValue; // get name of return type if (m_fgs.m_returnTypeName.Length == 0) { m_returnType = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue); m_fgs.m_returnTypeName = m_returnType.GetName(); } else { m_returnType = m_specification.GetType(m_fgs.m_returnTypeName); } } catch (System.Exception) { // sin/cos/sinh/cosh/exp(any SMV) // determine return type ComputeReturnTypeExpSmv(tmpFAI, FT); m_inputTypeName = tmpFAI[0].TypeName; m_fgs.m_returnTypeName = m_returnTypeName; } } }
/// <summary> /// Computes the return type for exp(smv). /// Sets m_returnTypeName and m_returnType. /// </summary> protected void ComputeReturnTypeExpSmv(G25.CG.Shared.FuncArgInfo[] FAI, G25.FloatType FT) { m_returnTypeName = m_fgs.ReturnTypeName; if (m_returnTypeName.Length == 0) { // find out returntype G25.SMV inputType = FAI[0].Type as G25.SMV; { // determine tight return type (i.e., keep repeating the geometric product of the input type until no more new basis blades are found) // We want to known which basis blades are present in inputType-to-the-power-of-infinity // So which bases blades will be present in the return type? bool[] present = new bool[1 << m_specification.m_dimension]; { bool[] tried = new bool[(1 << m_specification.m_dimension) * (1 << m_specification.m_dimension)]; // init 'present' with the inputType for (int i = 0; i < inputType.NbCoordinates; i++) { present[inputType.Group(0)[i].bitmap] = true; } // combine bitmaps (gp) until no more new bitmaps found bool newBBfound = true; while (newBBfound) { newBBfound = false; for (uint i = 0; i < present.Length; i++) { if (!present[i]) continue; for (uint j = 0; j < present.Length; j++) { if (!present[j]) continue; if (tried[j * (1 << m_specification.m_dimension) + i]) continue; // remember that we tried this combo of input blades: tried[j * (1 << m_specification.m_dimension) + i] = true; RefGA.Multivector M = RefGA.Multivector.gp(new RefGA.Multivector(new RefGA.BasisBlade(i)), new RefGA.Multivector(new RefGA.BasisBlade(j)), m_G25M.m_metric); for (int k = 0; k < M.BasisBlades.Length; k++) { uint b = M.BasisBlades[k].bitmap; if (!present[b]) { // this bitmap wasn't found yet, so mark it as present newBBfound = true; present[b] = true; } } } } } // end of combine bitmaps (gp) until no more new bitmaps found } // construct multivector of return type, get return type { System.Collections.ArrayList L = new System.Collections.ArrayList(); for (uint i = 0; i < present.Length; i++) { if (!present[i]) continue; else L.Add(new RefGA.BasisBlade(i, 1.0, "c" + i)); } RefGA.Multivector RTMV = new RefGA.Multivector(L); m_returnType = CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, RTMV) as G25.SMV; m_returnTypeName = m_returnType.GetName(); } } } // end of 'find out return type name' else { m_returnType = m_specification.GetType(m_returnTypeName); } }
/// <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; }
/// <summary> /// Writes a function to set a GOM struct according to vector images, 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> /// <param name="FT">Float type.</param> /// <param name="matrixMode">When true, generates code for setting from matrix instead of vector images.</param> /// <param name="transpose">When this parameter is true and <c>matrixMode</c> is true, generates code for setting from transpose matrix.</param> public static void WriteSetVectorImages(Specification S, G25.CG.Shared.CGdata cgd, FloatType FT, bool matrixMode, bool transpose) { G25.GOM gom = S.m_GOM; // get the 'plan' on how to initialize all domain basis blades efficiently: uint[][][] plan = G25.CG.Shared.OMinit.ComputeOmInitFromVectorsPlan(S, gom); double[][] signs = G25.CG.Shared.OMinit.ComputeOmInitFromVectorsSigns(S, gom, plan); // get range vector type G25.SMV rangeVectorType = G25.CG.Shared.OMinit.GetRangeVectorType(S, FT, cgd, gom); // setup array of arguments, function specification, etc int NB_ARGS = (matrixMode) ? 1 : gom.DomainVectors.Length; string[] argTypes = new string[NB_ARGS], argNames = new string[NB_ARGS]; RefGA.Multivector[] symbolicBBvalues = new RefGA.Multivector[1 << S.m_dimension]; // symbolic basis blade values go here if (matrixMode) { argTypes[0] = FT.type; argNames[0] = "M"; // convert matrix columns to symbolic Multivector values for (int d = 0; d < gom.DomainVectors.Length; d++) { RefGA.BasisBlade[] IV = new RefGA.BasisBlade[gom.RangeVectors.Length]; for (int r = 0; r < gom.RangeVectors.Length; r++) { int matrixIdx = (transpose) ? (d * gom.RangeVectors.Length + r) : (r * gom.DomainVectors.Length + d); string entryName = argNames[0] + "[" + matrixIdx + "]"; IV[r] = new RefGA.BasisBlade(gom.RangeVectors[r].bitmap, 1.0, entryName); } symbolicBBvalues[gom.DomainVectors[d].bitmap] = new RefGA.Multivector(IV); } } else { for (int d = 0; d < NB_ARGS; d++) { argTypes[d] = rangeVectorType.Name; argNames[d] = "i" + gom.DomainVectors[d].ToLangString(S.m_basisVectorNames); bool ptr = S.OutputC(); symbolicBBvalues[gom.DomainVectors[d].bitmap] = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(S, rangeVectorType, argNames[d], ptr); } } // generate function names for all grades (basis blade names not included) string typeName = FT.GetMangledName(S, gom.Name); string[] funcNames = GetSetFromLowerGradeFunctionNames(S, FT, matrixMode); // setup instructions (for main function, and subfunctions for grades) List<G25.CG.Shared.Instruction> mainI = new List<G25.CG.Shared.Instruction>(); List<G25.CG.Shared.Instruction>[] bladeI = new List<G25.CG.Shared.Instruction>[1 << S.m_dimension]; { bool mustCast = false; int nbTabs = 1; string dstName = (S.OutputC()) ? G25.fgs.RETURN_ARG_NAME : SmvUtil.THIS; bool dstPtr = S.OutputCppOrC(); bool declareDst = false; for (int g = 1; g < gom.Domain.Length; g++) { for (int d = 0; d < gom.DomainForGrade(g).Length; d++) { G25.SMVOM smvOM = gom.DomainSmvForGrade(g)[d]; RefGA.BasisBlade domainBlade = gom.DomainForGrade(g)[d]; if (g > 1) { bladeI[domainBlade.bitmap] = new List<G25.CG.Shared.Instruction>(); string funcCallCode = funcNames[g] + "_" + d + "("; if (S.OutputC()) funcCallCode += G25.fgs.RETURN_ARG_NAME; funcCallCode += ");"; mainI.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, funcCallCode)); } // follow the plan RefGA.Multivector value = new RefGA.Multivector(signs[g][d]); uint[] P = plan[g][d]; for (int p = 0; p < P.Length; p++) value = RefGA.Multivector.op(value, symbolicBBvalues[P[p]]); // add instructions List<G25.CG.Shared.Instruction> I = (g == 1) ? mainI : bladeI[domainBlade.bitmap]; I.Add(new G25.CG.Shared.CommentInstruction(nbTabs, "Set image of " + domainBlade.ToString(S.m_basisVectorNames))); I.Add(new G25.CG.Shared.AssignInstruction(nbTabs, smvOM, FT, mustCast, value, dstName, dstPtr, declareDst)); // store symbolic value symbolicBBvalues[domainBlade.bitmap] = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(S, smvOM, dstName, dstPtr); } } } // output grade > 1 functions if (cgd.generateOmInitCode(FT.type)) { for (int g = 2; g < gom.Domain.Length; g++) { for (int d = 0; d < gom.DomainForGrade(g).Length; d++) { RefGA.BasisBlade domainBlade = gom.DomainForGrade(g)[d]; string funcName = funcNames[g] + "_" + d; G25.fgs F = new G25.fgs(funcName, funcName, "", new string[0], new string[0], new string[] { FT.type }, null, null, null); // null, null = metricName, comment, options //F.InitArgumentPtrFromTypeNames(S); bool computeMultivectorValue = false; G25.CG.Shared.FuncArgInfo returnArgument = null; if (S.OutputC()) returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, FT, gom.Name, computeMultivectorValue); int nbArgs = 0; G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(S, F, nbArgs, FT, S.m_GMV.Name, computeMultivectorValue); Comment comment; comment = new Comment("Sets grade " + g + " part of outermorphism matrix based on lower grade parts."); bool inline = false; // do not inline this potentially huge function bool staticFunc = false; bool writeDecl = S.OutputC(); G25.CG.Shared.Functions.WriteFunction(S, cgd, F, inline, staticFunc, "void", funcName, returnArgument, FAI, bladeI[domainBlade.bitmap], comment, writeDecl); } } } { // output grade 1 function G25.fgs F = new G25.fgs(funcNames[1], funcNames[1], "", argTypes, argNames, new string[] { FT.type }, null, null, null); // null, null = metricName, comment, options F.InitArgumentPtrFromTypeNames(S); if (matrixMode) { F.m_argumentPtr[0] = S.OutputCppOrC(); F.m_argumentArr[0] = S.OutputCSharpOrJava(); } bool computeMultivectorValue = false; G25.CG.Shared.FuncArgInfo returnArgument = null; if (S.OutputC()) returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, FT, gom.Name, computeMultivectorValue); G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(S, F, NB_ARGS, FT, S.m_GMV.Name, computeMultivectorValue); Comment comment; if (!matrixMode) comment = new Comment("Sets " + typeName + " from images of the domain vectors."); else comment = new Comment("Sets " + typeName + " from a " + (transpose ? "transposed " : "") + "matrix"); bool inline = false; // do not inline this potentially huge function bool staticFunc = false; bool writeDecl = S.OutputC(); G25.CG.Shared.Functions.WriteFunction(S, cgd, F, inline, staticFunc, "void", funcNames[1], returnArgument, FAI, mainI, comment, writeDecl); } }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) m_fgs.m_argumentTypeNames = new string[] { m_gmv.Name }; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !tmpFAI[0].IsScalarOrSMV(); // compute intermediate results, set return type if (m_gmvFunc) m_fgs.m_returnTypeName = m_gmv.Name; // unit(gmv) = gmv else { m_smv = tmpFAI[0].Type as G25.SMV; // get symbolic result m_grade0Value = tmpFAI[0].MultivectorValue[0].ExtractGrade(0); m_grade2Value = tmpFAI[0].MultivectorValue[0].ExtractGrade(2); RefGA.Multivector reverseGrade2Value = RefGA.Multivector.Reverse(m_grade2Value); m_grade2norm2Value = RefGA.Multivector.gp(reverseGrade2Value, m_grade2Value, m_M); m_returnValue = RefGA.Multivector.gp(m_grade2Value, new RefGA.Multivector(mulName)); // where mulName = atan2(sqrt(grade2norm2), grade0) / sqrt(grade2norm2) // get name of return type if (m_fgs.m_returnTypeName.Length == 0) m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } m_returnType = m_specification.GetType(m_fgs.m_returnTypeName); }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name, m_gmv.Name }; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !(tmpFAI[0].IsScalarOrSMV() && tmpFAI[1].IsScalarOrSMV()); m_trueGmvFunc = (!tmpFAI[0].IsScalarOrSMV()) && (!tmpFAI[1].IsScalarOrSMV()); m_arg1isGmv = !tmpFAI[0].IsScalarOrSMV(); m_arg2isGmv = !tmpFAI[1].IsScalarOrSMV(); m_smv1 = tmpFAI[0].Type as G25.SMV; m_smv2 = tmpFAI[1].Type as G25.SMV; // compute intermediate results, set return type if (m_gmvFunc) m_fgs.m_returnTypeName = m_gmv.Name;// gmv * gmv = gmv else { // compute return value m_reverseValue = RefGA.Multivector.Reverse(tmpFAI[1].MultivectorValue[0]); m_n2Value = RefGA.Multivector.gp(m_reverseValue, tmpFAI[1].MultivectorValue[0], m_M); if (m_G25M.m_round) m_n2Value = m_n2Value.Round(1e-14); //m_returnValue = RefGA.Multivector.gp(RefGA.Multivector.gp(tmpFAI[0].MultivectorValue[0], m_reverseValue, m_M), // RefGA.Symbolic.ScalarOp.Inverse(new RefGA.Multivector(new RefGA.BasisBlade(0, 1.0, m_normSquaredName)))); m_returnValue = RefGA.Multivector.gp(tmpFAI[0].MultivectorValue[0], m_reverseValue, m_M); // round value if required by metric if (m_G25M.m_round) m_returnValue = m_returnValue.Round(1e-14); // get name of return type if (m_fgs.m_returnTypeName.Length == 0) m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name }; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !tmpFAI[0].IsScalarOrSMV(); // compute intermediate results, set return type if (m_gmvFunc) m_fgs.m_returnTypeName = m_gmv.Name; // dual(gmv) = gmv else { m_smv = tmpFAI[0].Type as G25.SMV; // get symbolic result m_reverseValue = RefGA.Multivector.Reverse(tmpFAI[0].MultivectorValue[0]); m_n2Value = RefGA.Multivector.gp(m_reverseValue, tmpFAI[0].MultivectorValue[0], m_M); if (m_G25M.m_round) m_n2Value = m_n2Value.Round(1e-14); if (m_n2Value.HasSymbolicScalars() || (!m_n2Value.IsScalar()) || m_n2Value.IsZero()) { m_inverseValue = RefGA.Multivector.gp(m_reverseValue, RefGA.Symbolic.UnaryScalarOp.Inverse(new RefGA.Multivector(new RefGA.BasisBlade(0, 1.0, m_normSquaredName)))); } else { m_inverseValue = RefGA.Multivector.gp(m_reverseValue, new RefGA.Multivector(1.0 / m_n2Value.RealScalarPart())); m_n2Value = null; } // get name of return type if (m_fgs.m_returnTypeName.Length == 0) m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_inverseValue).GetName(); } m_returnType = m_specification.GetType(m_fgs.m_returnTypeName); }
/// <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 }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { m_gradeIdx = GetGradeIdx(m_fgs.Name); // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) m_fgs.m_argumentTypeNames = new string[] { m_gmv.Name }; // supplement the extra 'int' argument if ((m_gradeIdx < 0) && (m_fgs.ArgumentTypeNames.Length == 1)) { m_fgs.m_argumentTypeNames = new string[] { m_fgs.ArgumentTypeNames[0], G25.GroupBitmapType.GROUP_BITMAP }; m_fgs.m_argumentVariableNames = new string[] { m_fgs.m_argumentVariableNames[0], "groupBitmap" }; } // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !tmpFAI[0].IsScalarOrSMV(); m_smv = tmpFAI[0].Type as G25.SMV; // compute intermediate results, set return type if (m_gmvFunc) m_fgs.m_returnTypeName = m_gmv.Name; // grade(gmv) = gmv else { // compute return value m_returnValue = tmpFAI[0].MultivectorValue[0].ExtractGrade(m_gradeIdx); // get name of return type if (m_fgs.m_returnTypeName.Length == 0) m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } }
/// <summary> /// Writes the 'explicit' declaration/definitions of 'F' to StringBuffer 'SB', taking into account parameters specified in specification 'S'. /// /// This function is called by the non-explicit version of the function. /// </summary> public void WriteExFunction(FloatType FT, string exFuncName) { G25.SMV smv = m_specification.GetSMV(m_SMVname); string randFuncCall = FT.DoubleToString(m_specification, -1.0) + " + " + FT.DoubleToString(m_specification, 2.0) + " * " + m_randomScalarFunc[FT.type] + "()"; // construct a explicit FGS string[] exArgumentTypeNames = new string[] { FT.type, FT.type, FT.type }; string[] exVariableNames = { m_fgs.ArgumentVariableNames[0], MINIMUM_NORM, LARGEST_COORDINATE }; fgs exFgs = new fgs(m_fgs.Name, m_fgs.OutputName, m_fgs.ReturnTypeName, exArgumentTypeNames, exVariableNames, m_fgs.FloatNames, m_fgs.MetricName, m_fgs.Comment, m_fgs.Options); exFgs.InitArgumentPtrFromTypeNames(m_specification); bool computeMultivectorValue = false; int nbArgs = 3; G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, exFgs, nbArgs, FT, FT.type, computeMultivectorValue); // because of lack of overloading, function names include names of argument types //G25.fgs CF = G25.CG.Shared.Util.AppendTypenameToFuncName(m_specification, FT, exFgs, FAI); G25.fgs CF = new G25.fgs(exFgs, exFuncName); //string exFuncName = funcName; // setup code to recursively call exFuncName string exFuncCall = ""; { StringBuilder exFuncCallSB = new StringBuilder(); if (!m_specification.OutputC()) exFuncCallSB.Append("return "); exFuncCallSB.Append(exFuncName); exFuncCallSB.Append("("); if (m_specification.OutputC()) { exFuncCallSB.Append(fgs.RETURN_ARG_NAME); exFuncCallSB.Append(", "); } for (int i = 0; i < exVariableNames.Length; i++) { if (i > 0) exFuncCallSB.Append(", "); exFuncCallSB.Append(exVariableNames[i]); } exFuncCallSB.AppendLine(");"); if (m_specification.OutputC()) { exFuncCallSB.AppendLine("return;"); } exFuncCall = exFuncCallSB.ToString(); } // generate a random SMV: RefGA.Multivector randomSMV = null; // get highest grade and bitmap of int hg = smv.HighestGrade(); // what is the highest non-zero grade of the type? uint bvBitmap = smv.BasisVectorBitmap(); // which basis vectors are used in the type? // setup random value to be returned if (InitWithRandomCoordinates(m_specification, smv)) { // set all coordinates to random values randomSMV = RefGA.Multivector.ZERO; for (int b = 0; b < smv.NbNonConstBasisBlade; b++) { randomSMV = RefGA.Multivector.Add(randomSMV, RefGA.Multivector.gp(new RefGA.Multivector(smv.NonConstBasisBlade(b)), new RefGA.Multivector("r" + smv.NonConstBasisBlade(b).ToLangString(m_specification.m_basisVectorNames)))); } } else { // set to geometric product of random vectors randomSMV = RefGA.Multivector.ONE; RefGA.Multivector randomVector; RefGA.BasisBlade[] B = new RefGA.BasisBlade[(int)RefGA.Bits.BitCount(bvBitmap)]; for (int g = 0; g < hg; g++) { int cnt = 0; for (int v = 0; v < m_specification.m_dimension; v++) { if ((bvBitmap & (uint)(1 << v)) != 0) { B[cnt] = new RefGA.BasisBlade((uint)(1 << v), 1.0, "r" + g + "_" + m_specification.m_basisVectorNames[v]); cnt++; } } randomVector = new RefGA.Multivector(B); randomSMV = RefGA.Multivector.gp(randomSMV, randomVector, m_G25M.m_metric); } // round value if required by metric if (m_G25M.m_round) randomSMV = randomSMV.Round(1e-14); } // setup instructions System.Collections.Generic.List<G25.CG.Shared.Instruction> I = new System.Collections.Generic.List<G25.CG.Shared.Instruction>(); { int nbTabs = 1; if (!smv.IsConstant()) { string smvTypeName = FT.GetMangledName(m_specification, m_SMVname); // SMV tmp; // double n, mul, lc; if (m_specification.OutputCppOrC()) I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, smvTypeName + " tmp;")); else I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, smvTypeName + " tmp = new " + smvTypeName + "();")); I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, FT.type + " n, mul, lc;")); I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, CodeUtil.GetBoolType(m_specification) + " nullBlade;")); // double rCoord = randomValue(), ....; StringBuilder randSB = new StringBuilder(); randSB.Append(FT.type); randSB.Append(" "); if (InitWithRandomCoordinates(m_specification, smv)) { // random coordinates for (int b = 0; b < smv.NbNonConstBasisBlade; b++) { if (b > 0) randSB.Append(", "); randSB.Append("r" + smv.NonConstBasisBlade(b).ToLangString(m_specification.m_basisVectorNames)); randSB.Append(" = "); randSB.Append(randFuncCall); } } else { // random vectors bool first = true; for (int g = 0; g < hg; g++) { for (int v = 0; v < m_specification.m_dimension; v++) { if (!first) randSB.Append(", "); first = false; if ((g > 0) && (v == 0)) { randSB.AppendLine(""); // newline randSB.Append("\t\t"); } randSB.Append("r" + g + "_" + m_specification.m_basisVectorNames[v]); randSB.Append(" = "); randSB.Append(randFuncCall); } } } randSB.Append(";"); I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, randSB.ToString())); // SMV tmp = random; bool mustCast = false; bool randomPtr = false; bool declareRandom = false; I.Add(new G25.CG.Shared.AssignInstruction(nbTabs, smv, FT, mustCast, randomSMV, "tmp", randomPtr, declareRandom)); // n = norm_ret_scalar(tmp); string emp = (m_specification.OutputC()) ? "&" : ""; I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, "n = " + m_normFunc[FT.type] + "(" + emp + "tmp);")); // lc = largestCoordinate(tmp); if (m_specification.OutputC()) { I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, "lc = " + smvTypeName + "_largestCoordinate(&tmp);")); } else { string lcStr = "largestCoordinate"; if (m_specification.OutputCSharp()) lcStr = "LargestCoordinate"; I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, "lc = tmp." + lcStr + "();")); } // null = (n == 0) && (lc ! 0) if ((m_smvType.MvType == SMV.MULTIVECTOR_TYPE.ROTOR) || (m_smvType.MvType == SMV.MULTIVECTOR_TYPE.VERSOR)) I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, "nullBlade = " + (m_specification.OutputC() ? "0" : "false") + ";")); else I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, "nullBlade = ((n == " + FT.DoubleToString(m_specification, 0.0) + ") && (lc != " + FT.DoubleToString(m_specification, 0.0) + "));")); // test minimumNorm I.Add(new CommentInstruction(nbTabs, "Recurse if generated random value has a norm below user-supplied limit, unless this is a null blade")); I.Add(new G25.CG.Shared.IfElseInstruction(nbTabs, "(n < " + exVariableNames[1] + ") && (!nullBlade)", new List<Instruction>() {new G25.CG.Shared.VerbatimCodeInstruction(nbTabs + 1, exFuncCall)}, // if instructions new List<Instruction>())); // else instructions // compute multiplier string lcCondition = "(lc * " + CodeUtil.OpNameToLangString(m_specification, FT, "abs") + "(mul)) > largestCoordinate "; I.Add(new CommentInstruction(nbTabs, "Compute multiplier")); I.Add(new G25.CG.Shared.IfElseInstruction(nbTabs, "n < " + FT.DoubleToString(m_specification, 0.0001), new List<Instruction>() { new G25.CG.Shared.VerbatimCodeInstruction(nbTabs + 1, "mul = " + FT.DoubleToString(m_specification, 1.0) + ";") }, // if instructions new List<Instruction>() { // else instructions new G25.CG.Shared.VerbatimCodeInstruction(nbTabs + 1, "mul = " + exFgs.ArgumentVariableNames[0] + " * (" + randFuncCall + ") / n;"), new CommentInstruction(nbTabs+1, "Test largest coordinate"), new G25.CG.Shared.IfElseInstruction(nbTabs+1, lcCondition, new List<Instruction>() { new G25.CG.Shared.VerbatimCodeInstruction(nbTabs + 2, exFuncCall) }, // if instructions new List<Instruction>()) })); // test largest coordinate //I.Add(new CommentInstruction(nbTabs, "Test largest coordinate")); //I.Add(new G25.CG.Shared.IfElseInstruction(nbTabs, lcCondition, // new List<Instruction>() { new G25.CG.Shared.VerbatimCodeInstruction(nbTabs + 1, exFuncCall) }, // if instructions // new List<Instruction>())); // else instructions // return tmp*mul; I.Add(new CommentInstruction(nbTabs, "Apply multiplier, return")); RefGA.Multivector tmpValue = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(m_specification, smv, "tmp", false); RefGA.Multivector returnValue = RefGA.Multivector.gp(tmpValue, new RefGA.Multivector("mul")); I.Add(new G25.CG.Shared.ReturnInstruction(nbTabs, smv, FT, mustCast, returnValue)); } // end of '!IsConstant()'? else { // the user wants a 'random' constant: simply return the constant itself. RefGA.Multivector returnValue = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(m_specification, smv, "tmp", false); bool mustCast = false; I.Add(new G25.CG.Shared.ReturnInstruction(nbTabs, smv, FT, mustCast, returnValue)); } } // because of lack of overloading, function names include names of argument types //G25.fgs CF = G25.CG.Shared.Util.AppendTypenameToFuncName(m_specification, FT, exFgs, FAI); // generate comment Comment comment = new Comment(exFgs.AddUserComment("Returns random " + m_SMVname + " with a scale in the interval [0, scale)")); bool staticFunc = Functions.OutputStaticFunctions(m_specification); G25.CG.Shared.Functions.WriteFunction(m_specification, m_cgd, CF, m_specification.m_inlineFunctions, staticFunc, exFuncName, FAI, I, comment); }
/// <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) { StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; defSB.AppendLine(""); foreach (G25.FloatType FT in S.m_floatTypes) { foreach (G25.SMV smv in S.m_SMV) { if (smv.NbNonConstBasisBlade == 0) continue; String className = FT.GetMangledName(S, smv.Name); String funcName = className + "::set"; 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.SetArgumentPtr(1, true); // second argument is a pointer to 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 = true; G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd, S.m_inlineSet, "void", null, funcName, null, FAI, FT, mustCast, smv, dstName, dstPtr, mvValue); } } }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { // get info on # arguments m_isUnit = IsApplyUnitVersor(m_fgs) || IsApplyVersorWI(m_fgs); // unit or inverse provided? NB_ARGS = GetNbArgs(m_fgs); // number of arguments (2 or 3) // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) { m_fgs.m_argumentTypeNames = new String[NB_ARGS]; for (int i = 0; i < NB_ARGS; i++) m_fgs.m_argumentTypeNames[i] = m_gmv.Name; } // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !(tmpFAI[0].IsScalarOrSMV() && tmpFAI[1].IsScalarOrSMV()); m_versorMv = (G25.MV)tmpFAI[0].Type; m_subjectMv = (G25.MV)tmpFAI[1].Type; if (tmpFAI.Length > 2) m_inverseVersorMv = (G25.MV)tmpFAI[2].Type; { // get symbolic result // get grade of input blade: m_inputGradeUsage = tmpFAI[1].MultivectorValue[0].GradeUsage(); // get basic transformed value m_versorValue = tmpFAI[0].MultivectorValue[0]; m_reverseVersorValue = (IsApplyVersorWI(m_fgs)) ? tmpFAI[2].MultivectorValue[0] : RefGA.Multivector.Reverse(m_versorValue); m_transformedValue = RefGA.Multivector.gp( RefGA.Multivector.gp(m_versorValue, tmpFAI[1].MultivectorValue[0], m_M), m_reverseVersorValue, m_M); // apply grade part selection m_transformedValue = m_transformedValue.ExtractGrade(RefGA.Multivector.GradeBitmapToArray(m_inputGradeUsage)); // if rotor is not guaranteed by the user to be unit, compute norm squared if (!m_isUnit) m_n2Value = RefGA.Multivector.ip(m_reverseVersorValue, m_versorValue, m_M, RefGA.BasisBlade.InnerProductType.LEFT_CONTRACTION); // round value if required by metric if (m_G25M.m_round) { m_transformedValue = m_transformedValue.Round(1e-14); if (m_n2Value != null) m_n2Value = m_n2Value.Round(1e-14); } } // compute intermediate results, set return type if (m_gmvFunc) m_fgs.m_returnTypeName = m_gmv.Name; // gmv * gmv / gmv = gmv else { // get name of return type if (m_fgs.m_returnTypeName.Length == 0) m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_transformedValue).GetName(); } m_returnType = m_specification.GetType(m_fgs.m_returnTypeName); }
/// <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) { StringBuilder declSB = cgd.m_declSB; StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; declSB.AppendLine(""); defSB.AppendLine(""); foreach (G25.FloatType FT in S.m_floatTypes) { foreach (G25.SMV smv in S.m_SMV) { if (smv.GetElementIdx(RefGA.BasisBlade.ONE) < 0) continue; // if no scalar coordinate, continue string className = FT.GetMangledName(S, smv.Name); string funcName = className + "::set"; 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 returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, FT, smv.Name, computeMultivectorValue); 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 = true; G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd, S.m_inlineSet, "void", null, funcName, null, FAI, FT, mustCast, smv, dstName, dstPtr, mvValue); } } }
/// <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) { StringBuilder declSB = cgd.m_declSB; StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; declSB.AppendLine(""); defSB.AppendLine(""); foreach (G25.FloatType FT in S.m_floatTypes) { foreach (G25.SMV smv in S.m_SMV) { if (smv.NbNonConstBasisBlade == 0) continue; string typeName = FT.GetMangledName(S, smv.Name); string funcName = typeName + "_setArray"; bool mustCast = false; string[] argTypename = new string[1] { FT.type }; string[] argName = new string[1] { "A" }; System.Collections.ArrayList L = new System.Collections.ArrayList(); for (int i = 0; i < smv.NbNonConstBasisBlade; i++) { RefGA.BasisBlade B = smv.NonConstBasisBlade(i); //argTypename[i] = FT.type; String coordStr = argName[0] + "[" + i + "]"; //argName[i] = 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); F.SetArgumentPtr(0, true); // first argument is a pointer to array bool computeMultivectorValue = false; G25.CG.Shared.FuncArgInfo returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, FT, smv.Name, computeMultivectorValue); int nbArgs = 1; // one array of coordinates G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(S, F, nbArgs, FT, null, computeMultivectorValue); declSB.AppendLine("/** Sets " + typeName + " to specified coordinates */"); bool staticFunc = false; G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd, S.m_inlineSet, staticFunc, "void", null, funcName, returnArgument, FAI, FT, mustCast, smv, returnArgument.Name, returnArgument.Pointer, mvValue); } } }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// /// As the return type is required, many functions will also compute the return value and other info /// needed for generating the code inside this function. These intermediate values are then /// stored in class variables so they can be reused in WriteFunction() /// </summary> public override void CompleteFGS() { NB_ARGS = m_fgs.NbArguments; // all arguments must be explicitly listed // in C language, all arguments are pointers if (m_fgs.ArgumentPtr.Length == 0) { bool ptr = m_specification.OutputC(); m_fgs.m_argumentPtr = new bool[] { ptr, ptr }; m_fgs.m_argumentArr = new bool[] { false, false }; } // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_smv1 = tmpFAI[0].Type as G25.SMV; m_smv2 = tmpFAI[1].Type as G25.SMV; { // compute return value // compute symbolic distance squared value m_returnValue = RefGA.Multivector.gp( RefGA.Multivector.ScalarProduct(tmpFAI[0].MultivectorValue[0], tmpFAI[1].MultivectorValue[0], m_M), -2.0); // apply sqrt(fabs()) if distance should not be squared: if (IsDistance(m_fgs)) m_returnValue = RefGA.Symbolic.UnaryScalarOp.Sqrt(RefGA.Symbolic.UnaryScalarOp.Abs(m_returnValue)); // round value if required by metric if (m_G25M.m_round) m_returnValue = m_returnValue.Round(1e-14); } // get name of return type if (m_fgs.m_returnTypeName.Length == 0) m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) { if (m_specification.m_GOM == null) throw new G25.UserException("No general outermorphism type defined, while it is required because the type of the first argument was unspecified."); m_fgs.m_argumentTypeNames = new String[] { m_specification.m_GOM.Name, m_gmv.Name }; } // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_om = (G25.OM)tmpFAI[0].Type; m_mv = (G25.MV)tmpFAI[1].Type; m_gmvFunc = !tmpFAI[1].IsScalarOrSMV(); // compute intermediate results, set return type if (m_gmvFunc) m_fgs.m_returnTypeName = m_gmv.Name;// gmv + gmv = gmv else { RefGA.Multivector inputValue = tmpFAI[1].MultivectorValue[0]; // Compute m_returnValue: // Replace each basis blade in 'inputValue' with its value under the outermorphism. m_returnValue = RefGA.Multivector.ZERO; 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 = m_om.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 = m_specification.OutputC(); RefGA.Multivector omColumnValue = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(m_specification, m_om.DomainSmvForGrade(inputBlade.Grade())[c], tmpFAI[0].Name, ptr); RefGA.Multivector inputBladeScalarMultiplier = new RefGA.Multivector(new RefGA.BasisBlade(inputBlade, 0)); RefGA.Multivector domainBladeScalarMultiplier = new RefGA.Multivector(new RefGA.BasisBlade(domainBlades[c], 0)); m_returnValue = RefGA.Multivector.Add(m_returnValue, RefGA.Multivector.gp( RefGA.Multivector.gp(omColumnValue, inputBladeScalarMultiplier), domainBladeScalarMultiplier)); break; // no need to search the other domainBlades too } } } // get name of return type if (m_fgs.m_returnTypeName.Length == 0) m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } }
/// <summary> /// Should write the declaration/definitions of 'F' to StringBuffer 'SB', taking into account parameters specified in specification 'S'. /// </summary> public override void WriteFunction() { 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_gmv.Name, computeMultivectorValue); // generate comment Comment comment = new Comment( m_fgs.AddUserComment("Returns logarithm of " + FAI[0].TypeName + " using " + m_G25M.m_name + " metric, assuming a 3D Euclidean rotor.")); // if scalar or specialized: generate specialized function if (m_gmvFunc) { StringBuilder declSB = m_cgd.m_declSB; bool inline = false; // never inline GMV functions StringBuilder defSB = (inline) ? m_cgd.m_inlineDefSB : m_cgd.m_defSB; // 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; // setup hashtable with template arguments: System.Collections.Hashtable argTable = new System.Collections.Hashtable(); argTable["S"] = m_specification; argTable["functionName"] = m_funcName[FT.type]; argTable["FT"] = FT; argTable["mvType"] = FT.GetMangledName(m_specification, m_specification.m_GMV.Name); argTable["setPlaneFuncName"] = getSetPlaneFuncName(); argTable["scalarGpFuncName"] = m_scalarGpFunc[floatName]; argTable["norm2FuncName"] = m_norm2Func[floatName]; argTable["grade2FuncName"] = m_grade2Func[floatName]; if (m_specification.OutputCppOrC()) { // header m_cgd.m_cog.EmitTemplate(declSB, "logEuclideanHeader", argTable); } // source m_cgd.m_cog.EmitTemplate(defSB, "logEuclidean", argTable); } else {// write simple 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 nPtr = false; bool declareN = true; // get grade 2 norm, scalar part I.Add(new G25.CG.Shared.AssignInstruction(nbTabs, FT, FT, mustCast, m_grade2norm2Value, norm2Name, nPtr, declareN)); I.Add(new G25.CG.Shared.AssignInstruction(nbTabs, FT, FT, mustCast, m_grade0Value, scalarPartName, nPtr, declareN)); // setup checks for grade 2 == 0, grade 0 < 0.0 List<G25.CG.Shared.Instruction> specialI = new List<G25.CG.Shared.Instruction>(); List<G25.CG.Shared.Instruction> normalI = new List<G25.CG.Shared.Instruction>(); { // special cases // setup checks for grade 0 < 0.0 List<G25.CG.Shared.Instruction> ifI = new List<G25.CG.Shared.Instruction>(); List<G25.CG.Shared.Instruction> elseI = new List<G25.CG.Shared.Instruction>(); // either return PI * ANY_GRADE2_BLADE or 0 RefGA.Multivector arbRot360 = new RefGA.Multivector(new RefGA.BasisBlade(m_grade2Value.BasisBlades[0].bitmap, Math.PI)); ifI.Add(new G25.CG.Shared.ReturnInstruction(nbTabs + 2, m_returnType, FT, mustCast, arbRot360)); // return 360 degree rotation in arbitrary plane elseI.Add(new G25.CG.Shared.ReturnInstruction(nbTabs + 2, m_returnType, FT, mustCast, RefGA.Multivector.ZERO)); // return zero if grade2 == 0 and grade0 >= 0 specialI.Add(new G25.CG.Shared.IfElseInstruction(nbTabs + 1, scalarPartName + " < " + FT.DoubleToString(m_specification, 0.0), ifI, elseI)); } { // normal case // where mulName = atan2(sqrt(grade2norm2), grade0) / sqrt(grade2norm2) RefGA.Multivector normValue = new RefGA.Multivector(normName); RefGA.Multivector grade0Value = new RefGA.Multivector(scalarPartName); normalI.Add(new G25.CG.Shared.AssignInstruction(nbTabs + 1, FT, FT, mustCast, RefGA.Symbolic.UnaryScalarOp.Sqrt(new RefGA.Multivector(norm2Name)), normName, nPtr, declareN)); normalI.Add(new G25.CG.Shared.AssignInstruction(nbTabs + 1, FT, FT, mustCast, RefGA.Symbolic.BinaryScalarOp.Atan2(normValue, grade0Value), mulName, nPtr, declareN, "/", normValue)); // result = input / n2 normalI.Add(new G25.CG.Shared.ReturnInstruction(nbTabs + 1, m_returnType, FT, mustCast, m_returnValue)); } I.Add(new G25.CG.Shared.IfElseInstruction(nbTabs, norm2Name + " <= " + FT.DoubleToString(m_specification, 0.0), specialI, normalI)); } // 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); } } }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name, m_gmv.Name }; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !(tmpFAI[0].IsScalarOrSMV() && tmpFAI[1].IsScalarOrSMV()); m_smv1 = tmpFAI[0].Type as G25.SMV; m_smv2 = tmpFAI[1].Type as G25.SMV; // compute intermediate results, set return type if (m_gmvFunc) m_fgs.m_returnTypeName = m_gmv.Name; // gmv ^ gmv = gmv else { // compute return value m_returnValue = RefGA.Multivector.op(tmpFAI[0].MultivectorValue[0], tmpFAI[1].MultivectorValue[0]); // get name of return type if (m_fgs.m_returnTypeName.Length == 0) m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } }
public static void WriteSetMatrix(Specification S, G25.CG.Shared.CGdata cgd, FloatType FT, G25.SOM som, bool transpose) { int NB_ARGS = 1; string[] argTypes = new string[NB_ARGS]; string[] argNames = new string[NB_ARGS]; argTypes[0] = FT.type; argNames[0] = "M"; // construct image values RefGA.Multivector[] imageValue = new RefGA.Multivector[som.DomainVectors.Length]; for (int d = 0; d < som.DomainVectors.Length; d++) { //imageValue[d] = RefGA.Multivector.ZERO; RefGA.BasisBlade[] IV = new RefGA.BasisBlade[som.RangeVectors.Length]; for (int r = 0; r < som.RangeVectors.Length; r++) { int matrixIdx = (transpose) ? (d * som.RangeVectors.Length + r) : (r * som.DomainVectors.Length + d); string entryName = argNames[0] + "[" + matrixIdx + "]"; IV[r] = new RefGA.BasisBlade(som.RangeVectors[r].bitmap, 1.0, entryName); } imageValue[d] = new RefGA.Multivector(IV); } string typeName = FT.GetMangledName(S, som.Name); string funcName = GetFunctionName(S, typeName, "set", "_setMatrix"); if (transpose) funcName = funcName + "Transpose"; //argNames[0] = "*" + argNames[0]; // quick hack: add pointer to name instead of type! G25.fgs F = new G25.fgs(funcName, funcName, "", argTypes, argNames, new String[] { FT.type }, null, null, null); // null, null = metricName, comment, options F.InitArgumentPtrFromTypeNames(S); if (S.OutputCppOrC()) F.m_argumentPtr[0] = true; else F.m_argumentArr[0] = true; bool computeMultivectorValue = false; G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(S, F, NB_ARGS, FT, S.m_GMV.Name, computeMultivectorValue); G25.CG.Shared.FuncArgInfo returnArgument = null; if (S.OutputC()) returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, FT, som.Name, computeMultivectorValue); // setup instructions List<G25.CG.Shared.Instruction> I = new List<G25.CG.Shared.Instruction>(); { bool mustCast = false; int nbTabs = 1; string dstName = (S.OutputC()) ? G25.fgs.RETURN_ARG_NAME : SmvUtil.THIS; bool dstPtr = S.OutputCppOrC(); bool declareDst = false; for (int g = 1; g < som.Domain.Length; g++) { for (int c = 0; c < som.DomainForGrade(g).Length; c++) { G25.SMVOM smvOM = som.DomainSmvForGrade(g)[c]; RefGA.BasisBlade domainBlade = som.DomainForGrade(g)[c]; RefGA.Multivector value = new RefGA.Multivector(new RefGA.BasisBlade(domainBlade, 0)); // copy the scalar part, ditch the basis blade for (uint v = 0; v < som.DomainVectors.Length; v++) { if ((domainBlade.bitmap & som.DomainVectors[v].bitmap) != 0) { value = RefGA.Multivector.op(value, imageValue[v]); } } I.Add(new G25.CG.Shared.CommentInstruction(nbTabs, "Set image of " + domainBlade.ToString(S.m_basisVectorNames))); I.Add(new G25.CG.Shared.AssignInstruction(nbTabs, smvOM, FT, mustCast, value, dstName, dstPtr, declareDst)); } } } Comment comment = new Comment("Sets " + typeName + " from a " + (transpose ? "transposed " : "") + "matrix."); bool writeDecl = (S.OutputC()); bool staticFunc = false; G25.CG.Shared.Functions.WriteFunction(S, cgd, F, S.m_inlineSet, staticFunc, "void", funcName, returnArgument, FAI, I, comment, writeDecl); }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name, m_gmv.Name }; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !(tmpFAI[0].IsScalarOrSMV() && tmpFAI[1].IsScalarOrSMV()); m_smv1 = tmpFAI[0].Type as G25.SMV; m_smv2 = tmpFAI[1].Type as G25.SMV; // compute intermediate results, set return type if (m_gmvFunc) m_fgs.m_returnTypeName = m_gmv.Name; // gmv * gmv = gmv else { // compute return value if (IsInverse(m_fgs)) { m_returnValue = RefGA.Multivector.ihp(tmpFAI[0].MultivectorValue[0], tmpFAI[1].MultivectorValue[0]); } else { m_returnValue = RefGA.Multivector.hp(tmpFAI[0].MultivectorValue[0], tmpFAI[1].MultivectorValue[0]); } bool getReturnType = (m_fgs.m_returnTypeName.Length == 0); // get name of return type if (getReturnType) m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); // This code corrects the result for the signs of the basis blade, and loops until the return type converges. // The reason for this code is that the hadamard product is not well-defined when the basis blades of the operands and the result do not match. while (true) { G25.VariableType returnType = m_specification.GetType(m_fgs.m_returnTypeName); if (returnType is G25.SMV) { G25.SMV returnSMV = returnType as G25.SMV; RefGA.Multivector unitReturnSmv = returnSMV.ToMultivectorValue(); RefGA.Multivector correctedReturnValue = RefGA.Multivector.ihp(m_returnValue, unitReturnSmv); if (getReturnType) { string newReturnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); if (newReturnTypeName == m_fgs.m_returnTypeName) { m_returnValue = correctedReturnValue; break; } else m_fgs.m_returnTypeName = newReturnTypeName; } else { m_returnValue = correctedReturnValue; break; } } else break; } } }
public static void WriteSetVectorImages(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.SOM som) { G25.SMV rangeVectorType = G25.CG.Shared.OMinit.GetRangeVectorType(S, FT, cgd, som); // loop over som.DomainVectors // setup array of arguments, function specification, etc int NB_ARGS = som.DomainVectors.Length; string[] argTypes = new string[NB_ARGS]; string[] argNames = new string[NB_ARGS]; RefGA.Multivector[] argValue = new RefGA.Multivector[NB_ARGS]; for (int d = 0; d < NB_ARGS; d++) { argTypes[d] = rangeVectorType.Name; argNames[d] = "i" + som.DomainVectors[d].ToLangString(S.m_basisVectorNames); bool ptr = (S.OutputC()); argValue[d] = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(S, rangeVectorType, argNames[d], ptr); } string typeName = FT.GetMangledName(S, som.Name); string funcName = GetFunctionName(S, typeName, "set", "_setVectorImages"); G25.fgs F = new G25.fgs(funcName, funcName, "", argTypes, argNames, 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_ARGS, FT, S.m_GMV.Name, computeMultivectorValue); G25.CG.Shared.FuncArgInfo returnArgument = null; if (S.OutputC()) returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, FT, som.Name, computeMultivectorValue); // setup instructions List<G25.CG.Shared.Instruction> I = new List<G25.CG.Shared.Instruction>(); { bool mustCast = false; int nbTabs = 1; string dstName = (S.OutputC()) ? G25.fgs.RETURN_ARG_NAME : SmvUtil.THIS; bool dstPtr = S.OutputCppOrC(); bool declareDst = false; for (int g = 1; g < som.Domain.Length; g++) { for (int c = 0; c < som.DomainForGrade(g).Length; c++) { G25.SMVOM smvOM = som.DomainSmvForGrade(g)[c]; RefGA.BasisBlade domainBlade = som.DomainForGrade(g)[c]; RefGA.Multivector value = new RefGA.Multivector(new RefGA.BasisBlade(domainBlade, 0)); // copy the scalar part, ditch the basis blade for (uint v = 0; v < som.DomainVectors.Length; v++) { if ((domainBlade.bitmap & som.DomainVectors[v].bitmap) != 0) { value = RefGA.Multivector.op(value, argValue[v]); } } I.Add(new G25.CG.Shared.CommentInstruction(nbTabs, "Set image of " + domainBlade.ToString(S.m_basisVectorNames))); I.Add(new G25.CG.Shared.AssignInstruction(nbTabs, smvOM, FT, mustCast, value, dstName, dstPtr, declareDst)); } } } Comment comment = new Comment("Sets " + typeName + " from images of the domain vectors."); bool writeDecl = false; bool staticFunc = false; G25.CG.Shared.Functions.WriteFunction(S, cgd, F, S.m_inlineSet, staticFunc, "void", funcName, returnArgument, FAI, I, comment, writeDecl); }
/// <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> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// /// As the return type is required, many functions will also compute the return value and other info /// needed for generating the code inside this function. These intermediate values are then /// stored in class variables so they can be reused in WriteFunction() /// </summary> public override void CompleteFGS() { NB_ARGS = m_fgs.NbArguments; // all arguments must be explicitly listed // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); { // compute return value RefGA.Multivector no = GetOrigin(m_specification, m_fgs); RefGA.Multivector ni = GetInfinity(m_specification, m_fgs); // compose a vector value (the Euclidean part) RefGA.Multivector vectorValue = RefGA.Multivector.ZERO; if ((IsRandom(m_specification, m_fgs)) || (IsCoordBased(m_specification, m_fgs, FT))) { m_returnValue = no; for (int i = 0; i < m_specification.m_dimension - 2; i++) { string bvName = "e" + (i + 1).ToString(); // todo: this assumes a fixed name for the basis vectors. Make these names options? int bvIdx = m_specification.GetBasisVectorIndex(bvName); if (bvIdx < 0) throw new G25.UserException("Cannot find basis vector " + bvName, XML.FunctionToXmlString(m_specification, m_fgs)); RefGA.Multivector basisVector = RefGA.Multivector.GetBasisVector(bvIdx); if (IsRandom(m_specification, m_fgs)) vectorValue = RefGA.Multivector.Add(vectorValue, RefGA.Multivector.gp(new RefGA.Multivector("ce" + (i + 1).ToString()), basisVector)); else vectorValue = RefGA.Multivector.Add(vectorValue, RefGA.Multivector.gp(tmpFAI[i].MultivectorValue[0], basisVector)); } } else if (IsVectorBased(m_specification, m_fgs, FT)) { vectorValue = tmpFAI[0].MultivectorValue[0]; m_vectorType = tmpFAI[0].Type; } else if (IsFlatPointBased(m_specification, m_fgs, FT)) { m_flatPointType = tmpFAI[0].Type as G25.SMV; RefGA.BasisBlade.InnerProductType lc = RefGA.BasisBlade.InnerProductType.LEFT_CONTRACTION; RefGA.Multivector noni = RefGA.Multivector.OuterProduct(no, ni); // scale = no^ni . pointPair RefGA.Multivector scale = RefGA.Multivector.InnerProduct(noni, tmpFAI[0].MultivectorValue[0], m_M, lc).ScalarPart(); if (m_G25M.m_round) scale = scale.Round(1e-14); // sphere = no . pointPair RefGA.Multivector sphere = RefGA.Multivector.InnerProduct(no, tmpFAI[0].MultivectorValue[0], m_M, lc); // normalizedSphere = sphere / scale bool needToNormalize = (scale.HasSymbolicScalars() || (scale.RealScalarPart() != 1.0)); RefGA.Multivector normalizedSphere = (needToNormalize) ? RefGA.Multivector.gp(sphere, RefGA.Symbolic.UnaryScalarOp.Inverse(scale)) : sphere; // keep only euclidean vectors RefGA.Multivector euclMultivector = getSumOfUnitEuclideanBasisVectors(); // vector = sphere-noni m_pointPairVectorValue = RefGA.Multivector.hp(normalizedSphere, euclMultivector); // round vector if (m_G25M.m_round) m_pointPairVectorValue = m_pointPairVectorValue.Round(1e-14); // get type m_vectorType = (G25.SMV)G25.CG.Shared.SpecializedReturnType.FindTightestMatch(m_specification, m_pointPairVectorValue, FT); if (m_vectorType == null) { throw new G25.UserException("Missing Euclidean vector type; cannot construct conformal point from " + m_fgs.ArgumentTypeNames[0], XML.FunctionToXmlString(m_specification, m_fgs)); } // get 'value' (just a reference to the name of the variable where m_pointPairVectorValue will be stored. bool pointer = false; vectorValue = Symbolic.SMVtoSymbolicMultivector(m_specification, (G25.SMV)m_vectorType, VECTOR_NAME, pointer); } else { throw new G25.UserException("Invalid arguments specified.", XML.FunctionToXmlString(m_specification, m_fgs)); } { // add no and 0.5 vectorValue^2 ni RefGA.Multivector vectorValueSquared = RefGA.Multivector.scp(vectorValue, vectorValue); RefGA.Multivector niPart = RefGA.Multivector.gp( RefGA.Multivector.gp(vectorValueSquared, ni), 0.5); m_returnValue = RefGA.Multivector.Add(RefGA.Multivector.Add(no, vectorValue), niPart); } } // end of compute return value // get name of return type if (m_fgs.m_returnTypeName.Length == 0) m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { m_ipType = GetIpType(m_specification, m_fgs); // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name, m_gmv.Name }; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !(tmpFAI[0].IsScalarOrSMV() && tmpFAI[1].IsScalarOrSMV()); m_smv1 = tmpFAI[0].Type as G25.SMV; m_smv2 = tmpFAI[1].Type as G25.SMV; // compute intermediate results, set return type if (m_gmvFunc) { if (m_ipType != RefGA.BasisBlade.InnerProductType.SCALAR_PRODUCT) { m_fgs.m_returnTypeName = m_gmv.Name;// gmv * gmv = gmv } else { m_fgs.ReturnTypeName = FT.type; } } else { // compute return value m_returnValue = RefGA.Multivector.ip(tmpFAI[0].MultivectorValue[0], tmpFAI[1].MultivectorValue[0], m_M, m_ipType); // round value if required by metric if (m_G25M.m_round) m_returnValue = m_returnValue.Round(1e-14); // get name of return type if ((m_fgs.ReturnTypeName.Length == 0) && (m_ipType != RefGA.BasisBlade.InnerProductType.SCALAR_PRODUCT)) { m_fgs.ReturnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } else { m_fgs.ReturnTypeName = FT.type; } } }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name }; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !tmpFAI[0].IsScalarOrSMV(); m_isNorm2 = IsNorm2(m_fgs); // compute intermediate results, set return type if (m_gmvFunc) m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, new RefGA.Multivector("x")).GetName(); // norm(gmv) = scalar else { m_smv = tmpFAI[0].Type as G25.SMV; // compute return value if (m_isNorm2) m_returnValue = tmpFAI[0].MultivectorValue[0].Norm_r2(m_M); else m_returnValue = RefGA.Symbolic.UnaryScalarOp.Abs(tmpFAI[0].MultivectorValue[0].Norm_r(m_M)); // round value if required by metric if (m_G25M.m_round) m_returnValue = m_returnValue.Round(1e-14); // avoid null return value because that might return in getting the wrong return type RefGA.Multivector nonZeroReturnValue = (m_returnValue.IsZero()) ? RefGA.Multivector.ONE : m_returnValue; // get name of return type if (m_fgs.m_returnTypeName.Length == 0) m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, nonZeroReturnValue).GetName(); } }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { if (m_G25M.m_metric.IsDegenerate()) throw new G25.UserException("Cannot generate dual functions for degenerate metrics."); // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name }; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !tmpFAI[0].IsScalarOrSMV(); // compute intermediate results, set return type if (m_gmvFunc) m_fgs.m_returnTypeName = m_gmv.Name; // dual(gmv) = gmv else { m_smv = tmpFAI[0].Type as G25.SMV; // compute return value if (IsDual(m_fgs)) m_returnValue = RefGA.Multivector.Dual(tmpFAI[0].MultivectorValue[0], m_M); else if (IsUndual(m_fgs)) m_returnValue = RefGA.Multivector.Undual(tmpFAI[0].MultivectorValue[0], m_M); // round value if required by metric if (m_G25M.m_round) m_returnValue = m_returnValue.Round(1e-14); // get name of return type if (m_fgs.m_returnTypeName.Length == 0) m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } }
} // 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])); } }
/// <summary> /// If this FunctionGenerator can implement 'F', then this function should complete the (possible) /// blanks in 'F'. This means: /// - Fill in F.m_returnTypeName if it is empty /// - Fill in F.m_argumentTypeNames (and m_argumentVariableNames) if it is empty. /// </summary> public override void CompleteFGS() { FloatType FT = m_specification.GetFloatType(m_fgs.FloatNames[0]); // fill in ArgumentTypeNames if (m_fgs.ArgumentTypeNames.Length == 0) m_fgs.m_argumentTypeNames = new String[] { m_gmv.Name, FT.type }; // init argument pointers from the completed typenames (language sensitive); m_fgs.InitArgumentPtrFromTypeNames(m_specification); // get all function info bool computeMultivectorValue = true; G25.CG.Shared.FuncArgInfo[] tmpFAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, m_fgs, NB_ARGS, FT, m_specification.m_GMV.Name, computeMultivectorValue); m_gmvFunc = !tmpFAI[0].IsScalarOrSMV(); // compute intermediate results, set return type if (m_gmvFunc) m_fgs.m_returnTypeName = m_gmv.Name; // div(gmv, scalar) = gmv else { m_smv = tmpFAI[0].Type as G25.SMV; RefGA.Multivector inputValue = tmpFAI[0].MultivectorValue[0]; RefGA.Multivector divValue = RefGA.Symbolic.UnaryScalarOp.Inverse(new RefGA.Multivector(tmpFAI[1].Name)); m_returnValue = RefGA.Multivector.gp(inputValue, divValue); // get name of return type if (m_fgs.m_returnTypeName.Length == 0) m_fgs.m_returnTypeName = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue).GetName(); } }