} // end of WriteFunctions() /// <summary> /// Writes a simple function which assigns some value based on specialized multivectors or scalars to some variable. /// /// Used by a lot of simple C functions, like gp, op, lc. /// /// Somewhat obsolete (preferably, use the more generic, instruction based WriteFunction()). /// /// </summary> /// <param name="S">Specification of algebra.</param> /// <param name="cgd">Results go into cgd.m_defSB, and so on</param> /// <param name="F">The function generation specification.</param> /// <param name="FT">Default float pointer type.</param> /// <param name="FAI">Info on the arguments of the function.</param> /// <param name="value">The value to assign.</param> /// <param name="comment">Optional comment for function (can be null).</param> public static void WriteSpecializedFunction(Specification S, G25.CG.Shared.CGdata cgd, G25.fgs F, FloatType FT, G25.CG.Shared.FuncArgInfo[] FAI, RefGA.Multivector value, Comment comment) { // get return type (may be a G25.SMV or a G25.FloatType) G25.VariableType returnType = G25.CG.Shared.SpecializedReturnType.GetReturnType(S, cgd, F, FT, value); if (returnType == null) { throw new G25.UserException("Missing return type: " + G25.CG.Shared.BasisBlade.MultivectorToTypeDescription(S, value), XML.FunctionToXmlString(S, F)); } bool ptr = true; string dstName = G25.fgs.RETURN_ARG_NAME; //string dstTypeName = (returnType is G25.SMV) ? FT.GetMangledName((returnType as G25.SMV).Name) : (returnType as G25.FloatType).type; string funcName = F.OutputName; // write comment to declaration if (comment != null) { if (S.OutputCppOrC()) { comment.Write(cgd.m_declSB, S, 0); } else { comment.Write(cgd.m_defSB, S, 0); } } if ((returnType is G25.SMV) && (S.OutputC())) { bool mustCast = false; G25.SMV dstSmv = returnType as G25.SMV; G25.CG.Shared.FuncArgInfo returnArgument = null; returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, FT, dstSmv.Name, false); // false = compute value bool staticFunc = S.OutputCSharpOrJava(); G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd, S.m_inlineFunctions, staticFunc, "void", null, funcName, returnArgument, FAI, FT, mustCast, dstSmv, dstName, ptr, value); } else { G25.FloatType returnFT = ((returnType as G25.FloatType) == null) ? FT : (returnType as G25.FloatType); bool mustCast = false; for (int i = 0; i < FAI.Length; i++) { mustCast |= returnFT.MustCastIfAssigned(S, FAI[i].FloatType); } bool staticFunc = S.OutputCSharpOrJava(); G25.CG.Shared.Functions.WriteReturnFunction(S, cgd, S.m_inlineSet, staticFunc, funcName, FAI, FT, mustCast, returnType, value); } } // end of WriteSpecializedFunction()
/// <summary> /// Instruction for generating code for an assignment to or a return of a variable. /// </summary> /// <param name="nbTabs">How many tabs to put in front of code.</param> /// <param name="T">Type of assigned variable.</param> /// <param name="FT">Floating point type of coordinates of assigned variable.</param> /// <param name="mustCast">When assigning to variable, should the coordinates be cast to FT?</param> /// <param name="value">The assigned value.</param> public AssignOrReturnInstruction(int nbTabs, G25.VariableType T, G25.FloatType FT, bool mustCast, RefGA.Multivector value) : base(nbTabs) { m_type = T; m_floatType = FT; m_mustCast = mustCast; m_value = value; }
/// <summary> /// Instruction for generating code for an assignment to a variable, with an optional declration of that same variable. /// </summary> /// <param name="nbTabs">How many tabs to put in front of code.</param> /// <param name="T">Type of assigned variable.</param> /// <param name="FT">Floating point type of coordinates of assigned variable. If T is a floating point type, then is equal to T.</param> /// <param name="mustCast">When assigning to variable, should the coordinates be cast to FT?</param> /// <param name="value">The assigned value.</param> /// <param name="name">Name of assigned variable.</param> /// <param name="ptr">Is the assigned variable a pointer?</param> /// <param name="declareVariable">If true, code for declaring the variable is also generated.</param> public AssignInstruction(int nbTabs, G25.VariableType T, G25.FloatType FT, bool mustCast, RefGA.Multivector value, string name, bool ptr, bool declareVariable) : base(nbTabs, T, FT, mustCast, value) { m_name = name; m_ptr = ptr; m_declareVariable = declareVariable; }
/// <summary> /// 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> /// 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()
} // end of function FindTightestMatch() /// <summary> /// The user may have requested a return type (F.ReturnTypeName). /// In that case, the type with the same name is found, or an exception /// is thrown if it does not exists. /// /// Otherwise, finds the (tightest, best) return type for a function 'F' which /// returning the (symbolic) value 'value'. /// This may or may not result in an SMV being found. If no /// type is found and the return type is a scalar, then a floating /// point type may be returned. /// /// If no SMV type is found, then a new type is created, and an exception /// is thrown which described the missing type. /// </summary> /// <param name="S">The specification (used to find SMVs)</param> /// <param name="cgd">Not used currently.</param> /// <param name="F">Function description (used for user-specified return type).</param> /// <param name="FT">Floating point type used in function.</param> /// <param name="value">The symbolic return value.</param> /// <returns>The SMV, FloatType or null if none found.</returns> public static G25.VariableType GetReturnType(Specification S, CGdata cgd, G25.fgs F, FloatType FT, RefGA.Multivector value) { if ((F.ReturnTypeName != null) && (F.ReturnTypeName.Length > 0)) { // The user specified a return type G25.SMV returnSmv = S.GetSMV(F.ReturnTypeName); // is it a SMV? if (returnSmv != null) { return(returnSmv); } G25.FloatType returnFT = S.GetFloatType(F.ReturnTypeName); // is it a specific float? if (returnFT != null) { return(FT); //returnFT; } else if (F.ReturnTypeName == G25.XML.XML_SCALAR) // is it a unspecified float? { return(FT); } // type does not exist: abort (TODO: error message) else { throw new G25.UserException("Non-existant user-specified return type: " + F.ReturnTypeName, XML.FunctionToXmlString(S, F)); // non-existant return type } } else { G25.VariableType RT = FindTightestMatch(S, value, FT); if (RT != null) { return(RT); } else { return(CreateSyntheticSMVtype(S, cgd, FT, value)); } } }
/// <summary> /// 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); // comment Comment comment = new Comment( m_fgs.AddUserComment("Returns " + FAI[1].TypeName + " " + FAI[1].Name + " * " + FAI[0].TypeName + " " + FAI[0].Name + " + " + FAI[2].TypeName + " " + FAI[2].Name + ".")); // if scalar or specialized: generate specialized function if (m_gmvFunc) { G25.CG.Shared.GmvCASNparts.WriteSASfunction(m_specification, m_cgd, FT, FAI, m_fgs, comment); } else {// write specialized function: // setup instructions System.Collections.Generic.List <G25.CG.Shared.Instruction> I = new System.Collections.Generic.List <G25.CG.Shared.Instruction>(); { int nbTabs = 1; bool mustCast = false; G25.VariableType returnType = G25.CG.Shared.SpecializedReturnType.GetReturnType(m_specification, m_cgd, m_fgs, FT, m_returnValue); I.Add(new G25.CG.Shared.ReturnInstruction(nbTabs, returnType, FT, mustCast, m_returnValue)); } // 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); bool staticFunc = Functions.OutputStaticFunctions(m_specification); G25.CG.Shared.Functions.WriteFunction(m_specification, m_cgd, CF, m_specification.m_inlineFunctions, staticFunc, CF.OutputName, FAI, I, comment); } } } // end of WriteFunction
} // end of WriteDeclaration() /// <summary> /// Writes generic function based on Instructions. /// /// This version automatically figures out the return type (so it is recommended over the other WriteFunction()). /// </summary> /// <param name="S">Specification of algebra.</param> /// <param name="cgd">Results go into cgd.m_defSB, and so on</param> /// <param name="F">Function specification.</param> /// <param name="inline">When true, the code is inlined.</param> /// <param name="staticFunc">static function?</param> /// <param name="functionName">Name of generated function.</param> /// <param name="arguments">Arguments of function (any 'return argument' used for the C language is automatically setup correctly).</param> /// <param name="instructions">List of GA-instructions which make up the function.</param> /// <param name="comment">Comment to go into generated declration code.</param> public static void WriteFunction( Specification S, G25.CG.Shared.CGdata cgd, G25.fgs F, bool inline, bool staticFunc, string functionName, FuncArgInfo[] arguments, List <Instruction> instructions, Comment comment) { List <G25.VariableType> returnTypes = new List <G25.VariableType>(); List <G25.FloatType> returnTypeFT = new List <G25.FloatType>(); // floating point types of return types Instruction.GetReturnType(instructions, returnTypes, returnTypeFT); // for now, assume only one return type is used? string returnType = "void"; G25.CG.Shared.FuncArgInfo returnArgument = null; if (returnTypes.Count > 0) { G25.VariableType returnVT = returnTypes[0]; G25.FloatType returnFT = returnTypeFT[0]; if (returnVT is G25.FloatType) { returnVT = returnFT; } string returnTypeName = (returnVT is G25.MV) ? (returnVT as G25.MV).Name : (returnVT as FloatType).type; returnType = returnFT.GetMangledName(S, returnTypeName); if (S.OutputC()) { if (!(returnVT is G25.FloatType)) { returnArgument = new G25.CG.Shared.FuncArgInfo(S, F, -1, returnFT, returnTypeName, false); // false = compute value } } } WriteFunction(S, cgd, F, inline, staticFunc, returnType, functionName, returnArgument, arguments, instructions, comment); } // end of WriteFunction()
/// <summary> /// Writes all shortcuts for 'type'. /// </summary> /// <param name="SB">Where the code goes.</param> /// <param name="S">Used for namespace.</param> /// <param name="cgd">Not used yet.</param> /// <param name="FT">Float point type of 'type'.</param> /// <param name="type">The type for which the function should be written.</param> public static void WriteFunctionShortcuts(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd, FloatType FT, G25.VariableType type) { Dictionary <string, List <G25.Operator> > operatorMap = S.GetOperatorMap(); Dictionary <string, bool> boundOperators = new Dictionary <string, bool>(); foreach (G25.fgs fgs in S.m_functions) { if ((type is G25.SMV) && fgs.IsConverter(S)) { G25.SMV smv = (G25.SMV)type; if (fgs.IsConverterSource(S, (G25.SMV)type, FT)) { // write converter here . . . //SB.AppendLine("// converter source here!"); } else if (fgs.IsConverterDestination(S, smv, FT)) { // write converter here . . . Converter.WriteMemberConverter(SB, S, cgd, FT, fgs, (G25.SMV)S.GetType(fgs.ArgumentTypeNames[0]), smv); } } else if (fgs.GetSupportedByPlugin() && (fgs.NbArguments >= 1) && (Array.IndexOf(fgs.FloatNames, FT.type) >= 0)) { // get function arguments bool computeMultivectorValue = false; G25.CG.Shared.FuncArgInfo[] FAI = null; try { FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(S, fgs, fgs.NbArguments, FT, "not set", computeMultivectorValue); } catch (Exception ex) { if ((type is G25.GMV) && (FT == S.m_floatTypes[0])) // only warn once { Console.WriteLine("Warning: cannot generate shortcut to " + fgs.ToString()); } continue; } // if type matches, write the shortcut, and possibly an operator if (FAI[0].TypeName.Equals(type.GetName())) { WriteFunctionShortcut(SB, S, cgd, FT, type, fgs, FAI); if (S.OutputCSharpOrJava()) { removeMvInterfaces(FAI); // arguments to operators need to be of the multivector type, not the multivector interface type } WriteOperatorShortcut(SB, S, cgd, FT, type, fgs, FAI, operatorMap, boundOperators); } } } } // end of function WriteFunctionShortcuts()
/// <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> /// Checks if an operator should be written for the combination of 'type' and 'fgs'. /// </summary> /// <param name="SB">Where the code goes.</param> /// <param name="S">Used for basis vector names and output language.</param> /// <param name="cgd">Not used yet.</param> /// <param name="FT">Float point type of 'type'.</param> /// <param name="type">The type for which shortcuts should be written.</param> /// <param name="fgs"></param> /// <param name="FAI"></param> /// <param name="operatorMap"></param> /// <param name="boundOperators"></param> private static void WriteOperatorShortcut(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd, FloatType FT, G25.VariableType type, G25.fgs fgs, FuncArgInfo[] FAI, Dictionary <string, List <G25.Operator> > operatorMap, Dictionary <string, bool> boundOperators) { if (S.OutputJava() || S.OutputC()) { return; // cannot override operators in Java or C } // check for, get entry in operatorMap for fgs.OutputName if (!operatorMap.ContainsKey(fgs.OutputName)) { return; } List <G25.Operator> opList = operatorMap[fgs.OutputName]; // check if number of arguments matches foreach (G25.Operator op in opList) { if (op.NbArguments == fgs.NbArguments) { // check if this operator already bound to function with the same arguments string uniqueOpArgId = op.Symbol; for (int a = 0; a < fgs.NbArguments; a++) { uniqueOpArgId += "~_~" + fgs.m_argumentTypeNames[a]; } if (boundOperators.ContainsKey(uniqueOpArgId)) { continue; } else { boundOperators[uniqueOpArgId] = true; } WriteOperatorShortcut(SB, S, cgd, FT, type, fgs, FAI, op); } } }
private static void WriteOperatorShortcut(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd, FloatType FT, G25.VariableType type, G25.fgs fgs, FuncArgInfo[] FAI, G25.Operator op) { // C# does not allow return type of ++ or -- to be different from input type if (S.OutputCSharp() && (op.IsIncrement() || op.IsDecrement()) && (fgs.ReturnTypeName != type.GetName())) { return; } string operatorCall = getOperatorCall(S, fgs, FAI); SB.AppendLine(""); int nbTabs = 1; // output comment new Comment("operator for " + operatorCall).Write(SB, S, nbTabs); bool inline = false; bool staticFunc = true; string returnType = FT.GetMangledName(S, fgs.ReturnTypeName); FuncArgInfo returnArgument = null; SB.Append('\t', nbTabs); Functions.WriteDeclaration(SB, S, cgd, inline, staticFunc, returnType, "operator " + op.Symbol, returnArgument, FAI); SB.AppendLine(" {"); SB.Append('\t', nbTabs + 1); SB.Append("return "); SB.Append(operatorCall); SB.AppendLine(";"); SB.Append('\t', nbTabs); SB.AppendLine("}"); }
/// <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> /// Writes a shortcut for 'type', 'fgs'. /// </summary> /// <param name="SB">Where the code goes.</param> /// <param name="S">Used for basis vector names and output language.</param> /// <param name="cgd">Not used yet.</param> /// <param name="FT">Float point type of 'type'.</param> /// <param name="type">The type for which shortcuts should be written.</param> /// <param name="fgs"></param> /// <param name="FAI"></param> public static void WriteFunctionShortcut(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd, FloatType FT, G25.VariableType type, G25.fgs fgs, FuncArgInfo[] FAI) { int nbTabs = 1; FuncArgInfo[] tailFAI = getTail(FAI); string shortcutCall = getShortcutCall(S, fgs, tailFAI); SB.AppendLine(""); // output comment new Comment("shortcut to " + shortcutCall).Write(SB, S, nbTabs); bool inline = false; bool staticFunc = false; string returnType = FT.GetMangledName(S, fgs.ReturnTypeName); FuncArgInfo returnArgument = null; SB.Append('\t', nbTabs); Functions.WriteDeclaration(SB, S, cgd, inline, staticFunc, returnType, fgs.OutputName, returnArgument, tailFAI); SB.AppendLine(" {"); SB.Append('\t', nbTabs + 1); SB.Append("return "); SB.Append(shortcutCall); SB.AppendLine(";"); SB.Append('\t', nbTabs); SB.AppendLine("}"); }
/// <summary> /// Instruction for generating code for an assignment to a variable, with an optional declration of that same variable. /// </summary> /// <param name="nbTabs">How many tabs to put in front of code.</param> /// <param name="T">Type of assigned variable.</param> /// <param name="FT">Floating point type of coordinates of assigned variable.</param> /// <param name="mustCast">When assigning to variable, should the coordinates be cast to FT?</param> /// <param name="value">The assigned value.</param> /// <param name="name">Name of assigned variable.</param> /// <param name="ptr">Is the assigned variable a pointer?</param> /// <param name="declareVariable">If true, code for declraring the variable is also generated.</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 AssignInstruction(int nbTabs, G25.VariableType T, G25.FloatType FT, bool mustCast, RefGA.Multivector value, String name, bool ptr, bool declareVariable, String postOp, RefGA.Multivector postOpValue) : this(nbTabs, T, FT, mustCast, value, name, ptr, declareVariable) { m_postOp = postOp; m_postOpValue = postOpValue; }
} // end of WriteFunction /// <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); } } // end of ComputeReturnTypeExpSmv()
/// <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> /// 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> /// 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> /// 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; } } } // end of CompleteFGS()
/// <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 RefGA.Multivector value = tmpFAI[0].MultivectorValue[0]; RefGA.Multivector reverseValue = RefGA.Multivector.Reverse(value); RefGA.Multivector n2Value = RefGA.Multivector.gp(reverseValue, value, m_M); m_nValue = n2Value; if (!m_M.IsPositiveDefinite()) { m_nValue = RefGA.Symbolic.UnaryScalarOp.Abs(m_nValue); } m_nValue = RefGA.Symbolic.UnaryScalarOp.Sqrt(m_nValue); // round value if required by metric if (m_G25M.m_round) { m_nValue = m_nValue.Round(1e-14); } try // try to m_nValue = evaluate(m_nValue) { m_nValue = m_nValue.SymbolicEval(new RefGA.Symbolic.HashtableSymbolicEvaluator()); } catch (ArgumentException) { } if (m_nValue.HasSymbolicScalars() || (!m_nValue.IsScalar()) || m_nValue.IsZero()) { RefGA.Multivector inverseNValue = RefGA.Symbolic.UnaryScalarOp.Inverse(new RefGA.Multivector(normName)); m_returnValue = RefGA.Multivector.gp(value, inverseNValue); } else { // no extra step required m_returnValue = RefGA.Multivector.gp(value, new RefGA.Multivector(1.0 / m_nValue.RealScalarPart())); m_nValue = 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_returnValue).GetName(); } } m_returnType = m_specification.GetType(m_fgs.m_returnTypeName); }
/// <summary> /// Constructs a new FuncArgInfo class for a specific argument 'argIdx' of function 'F'. /// </summary> /// <param name="S">Used for retrieving the G25.VariableType of 'm_typeName'.</param> /// <param name="F">Function for which this FuncArgInfo describes an argument.</param> /// <param name="argIdx">Index of argument. Use -1 for artificial 'return argument' used for the C language.</param> /// <param name="FT">Floating point type of the type of the argument.</param> /// <param name="defaultTypeName">Name of the type of the argument.</param> /// <param name="computeMultivectorValue">Set to true to convert the type into symbolic code. Uses 'F' to obtain the actual name of the variable to use inside the symbolic multivector.</param> public FuncArgInfo(G25.Specification S, G25.fgs F, int argIdx, G25.FloatType FT, string defaultTypeName, bool computeMultivectorValue) { m_mvInterface = true; m_name = F.GetArgumentName(argIdx); m_typeName = F.GetArgumentTypeName(argIdx, defaultTypeName); m_type = S.GetType(m_typeName); m_varType = m_type.GetVariableType(); if (m_varType != VARIABLE_TYPE.FLOAT) m_floatType = FT; else m_floatType = S.GetFloatType(m_typeName); // set mangled type name (depends on whether type is scalar or not) if ((m_varType == VARIABLE_TYPE.FLOAT) || (m_varType == VARIABLE_TYPE.ENUM)) { m_mangledTypeName = m_typeName; } else { m_mangledTypeName = FT.GetMangledName(S, m_typeName); // temp (currently disabled) test for C# and Java // if (S.OutputCSharpOrJava() && (m_varType == VARIABLE_TYPE.GMV)) // m_mangledTypeName = m_mangledTypeName + G25.CG.Shared.Main.IF_SUFFIX; } // set pointer / non pointer flag m_pointer = F.GetArgumentPtr(S, argIdx); // set array flag m_array = F.GetArgumentArr(S, argIdx); m_constant = (argIdx >= 0); if (computeMultivectorValue) { if (m_varType == VARIABLE_TYPE.SMV) { m_multivectorValue = new RefGA.Multivector[1] { Symbolic.SMVtoSymbolicMultivector(S, (G25.SMV)m_type, m_name, m_pointer) }; } else if (m_varType == VARIABLE_TYPE.GMV) m_multivectorValue = Symbolic.GMVtoSymbolicMultivector(S, (G25.GMV)m_type, m_name, m_pointer, -1); // -1 = sym mv for all groups else if (m_varType == VARIABLE_TYPE.FLOAT) m_multivectorValue = new RefGA.Multivector[1] { Symbolic.ScalarToSymbolicMultivector(S, (G25.FloatType)m_type, m_name) }; else { // OM: do nothing? m_multivectorValue = null; } } }
/// <summary> /// Instruction for generating code for returning 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> /// <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 ReturnInstruction(int nbTabs, G25.VariableType T, G25.FloatType FT, bool mustCast, RefGA.Multivector value, String postOp, RefGA.Multivector postOpValue) : base(nbTabs, T, FT, mustCast, value, postOp, postOpValue) { }
/// <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_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; } } } }
/// <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 RefGA.Multivector value = tmpFAI[0].MultivectorValue[0]; RefGA.Multivector reverseValue = RefGA.Multivector.Reverse(value); RefGA.Multivector n2Value = RefGA.Multivector.gp(reverseValue, value, m_M); m_nValue = n2Value; if (!m_M.IsPositiveDefinite()) m_nValue = RefGA.Symbolic.UnaryScalarOp.Abs(m_nValue); m_nValue = RefGA.Symbolic.UnaryScalarOp.Sqrt(m_nValue); // round value if required by metric if (m_G25M.m_round) m_nValue = m_nValue.Round(1e-14); try // try to m_nValue = evaluate(m_nValue) { m_nValue = m_nValue.SymbolicEval(new RefGA.Symbolic.HashtableSymbolicEvaluator()); } catch (ArgumentException) { } if (m_nValue.HasSymbolicScalars() || (!m_nValue.IsScalar()) || m_nValue.IsZero()) { RefGA.Multivector inverseNValue = RefGA.Symbolic.UnaryScalarOp.Inverse(new RefGA.Multivector(normName)); m_returnValue = RefGA.Multivector.gp(value, inverseNValue); } else { // no extra step required m_returnValue = RefGA.Multivector.gp(value, new RefGA.Multivector(1.0 / m_nValue.RealScalarPart())); m_nValue = 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_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 }; // 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> /// 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. /// /// 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(); } } // end of CompleteFGS()