Ejemplo n.º 1
0
        /// <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");
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Writes code for return m_name.
        /// </summary>
        /// <param name="SB">Where the code goes.</param>
        /// <param name="S">Specification of algebra.</param>
        /// <param name="cgd">Not used yet.</param>
        public override void Write(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd)
        {
            if (m_type is G25.FloatType)
            {
                AppendTabs(SB);

                // Temp hack to override the float type:
                G25.FloatType FT = m_floatType; //m_type as G25.FloatType;

                // Should postops still be applied?  ApplyPostOp(S, plugins, cog, BL, valueStr);
                // Not required so far?
                SB.AppendLine(CodeUtil.GenerateScalarReturnCode(S, FT, m_mustCast, m_value));
            }
            else if (m_type is G25.SMV)
            {
                if (S.OutputC())
                {
                    bool ptr             = true;
                    bool declareVariable = false;
                    new AssignInstruction(m_nbTabs, m_type, m_floatType, m_mustCast, m_value, G25.fgs.RETURN_ARG_NAME, ptr, declareVariable, m_postOp, m_postOpValue).Write(SB, S, cgd);
                }
                else
                {
                    G25.SMV            smv = m_type as G25.SMV;
                    RefGA.BasisBlade[] BL  = BasisBlade.GetNonConstBladeList(smv);
                    bool     writeZeros    = true;
                    string[] valueStr      = CodeUtil.GetAssignmentStrings(S, m_floatType, m_mustCast, BL, m_value, writeZeros);

                    // apply post operation (like "/ n2")
                    ApplyPostOp(S, cgd, BL, valueStr);

                    SB.AppendLine(CodeUtil.GenerateReturnCode(S, smv, m_floatType, valueStr, m_nbTabs, writeZeros));
                }
            }
        }
Ejemplo n.º 3
0
        } // end of GenerateSMVassignmentCode

        public static string GenerateReturnCode(Specification S, G25.SMV smv, G25.FloatType FT, String[] valueStr, int nbTabs, bool writeZeros)
        {
            StringBuilder SB      = new StringBuilder();
            string        smvName = FT.GetMangledName(S, smv.Name);

            string STATIC_MEMBER_ACCESS = (S.OutputCpp()) ? "::" : ".";

            SB.Append('\t', nbTabs);
            SB.Append("return ");
            if (S.OutputCSharpOrJava())
            {
                SB.Append("new ");
            }
            SB.Append(smvName);
            SB.Append("(");
            if (valueStr.Length > 0)
            {
                SB.AppendLine(smvName + STATIC_MEMBER_ACCESS + SmvUtil.GetCoordinateOrderConstant(S, smv) + ",");
            }
            for (int i = 0; i < valueStr.Length; i++)
            {
                SB.Append('\t', nbTabs + 2);
                SB.Append(valueStr[i]);
                if (i < (valueStr.Length - 1))
                {
                    SB.Append(",");
                }
                SB.AppendLine(" // " + smv.NonConstBasisBlade(i).ToLangString(S.m_basisVectorNames));
            }
            SB.Append('\t', nbTabs + 1);
            SB.Append(");");

            return(SB.ToString());
        }
Ejemplo n.º 4
0
        } // end of function ScalarOpToLangString()

        /// <summary>
        /// Converts a <c>RefGA.Symbolic.BinaryScalarOpToLangString</c> to code.
        ///
        /// Handles special cases (such as inversion) and understands floating point
        /// types (e.g., <c>fabsf()</c> is used for floats and <c>fabs()</c> is used for doubles in C.
        /// </summary>
        /// <param name="S">Used for output language.</param>
        /// <param name="FT">Floating point type used.</param>
        /// <param name="Op">The operation to convert to code.</param>
        /// <returns>Code for implementing <c>Op</c>c>.</returns>
        public static string BinaryScalarOpToLangString(G25.Specification S, G25.FloatType FT, RefGA.Symbolic.BinaryScalarOp Op)
        {
            string value1Str = ScalarOpValueToLangString(S, FT, Op.value1);
            string value2Str = ScalarOpValueToLangString(S, FT, Op.value2);

            return(OpNameToLangString(S, FT, Op.opName) + "(" + value1Str + ", " + value2Str + ")");
        } // end of function BinaryScalarOpToLangString()
Ejemplo n.º 5
0
        } // end of WriteSetArray()

        /// <summary>
        /// Writes a function to copy the value of one SMV struct to another, for all floating point types.
        /// </summary>
        /// <param name="S">Used for basis vector names and output language.</param>
        /// <param name="cgd">Intermediate data for code generation. Also contains plugins and cog.</param>
        public static void WriteSetCopy(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.SMV smv)
        {
            cgd.m_defSB.AppendLine("");

            //string className = FT.GetMangledName(S, smv.Name);
            string funcName = GMV.GetSetFuncName(S);
            bool   mustCast = false;

            G25.fgs F = new G25.fgs(funcName, funcName, "", new string[] { smv.Name }, null, new string[] { FT.type }, null, null, null); // null, null, null = metricName, comment, options
            F.InitArgumentPtrFromTypeNames(S);
            bool computeMultivectorValue = false;
            int  nbArgs = 1;

            G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(S, F, nbArgs, FT, null, computeMultivectorValue);


            RefGA.Multivector value = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(S, smv, FAI[0].Name, FAI[0].Pointer);

            string dstName = G25.CG.Shared.SmvUtil.THIS;
            bool   dstPtr  = false;

            bool staticFunc = false;

            G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd,
                                                            S.m_inlineSet, staticFunc, "void", null, funcName, null, FAI, FT, mustCast, smv, dstName, dstPtr, value);
        } // end of WriteSetCopy()
Ejemplo n.º 6
0
        /// <summary>
        /// Converts a <c>RefGA.Symbolic.UnaryScalarOp</c> to code.
        ///
        /// Handles special cases (such as inversion) and understands floating point
        /// types (e.g., <c>fabsf()</c> is used for floats and <c>fabs()</c> is used for doubles in C.
        /// </summary>
        /// <param name="S">Used for output language.</param>
        /// <param name="FT">Floating point type used.</param>
        /// <param name="Op">The operation to convert to code.</param>
        /// <returns>Code for implementing <c>Op</c>c>.</returns>
        public static string UnaryScalarOpToLangString(G25.Specification S, G25.FloatType FT, RefGA.Symbolic.UnaryScalarOp Op)
        {
            string valueStr = ScalarOpValueToLangString(S, FT, Op.value);

            /*{
             *  if (!Op.value.IsScalar()) throw new Exception("G25.CG.Shared.BasisBlade.ScalarOpToLangString(): value should be scalar, found: " + Op.value.ToString(S.m_basisVectorNames));
             *  if (Op.value.IsZero()) valueStr = ScalarToLangString(S, FT, RefGA.BasisBlade.ZERO);
             *  else valueStr = ScalarToLangString(S, FT, Op.value.BasisBlades[0]);
             * }*/

            if (Op.opName == UnaryScalarOp.INVERSE)
            {
                if (FT.type == "float")
                {
                    return("1.0f / (" + valueStr + ")");
                }
                else if (FT.type == "double")
                {
                    return("1.0 / (" + valueStr + ")");
                }
                else
                {
                    return(FT.castStr + "1.0 / (" + valueStr + ")");
                }
            }
            else
            {
                return(OpNameToLangString(S, FT, Op.opName) + "(" + valueStr + ")");
            }
        } // end of function ScalarOpToLangString()
Ejemplo n.º 7
0
        } // 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()
Ejemplo n.º 8
0
 /// <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;
 }
Ejemplo n.º 9
0
 /// <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;
 }
Ejemplo n.º 10
0
 /// <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);
 }
Ejemplo n.º 11
0
        /// <summary>
        /// Writes code for m_name = m_value.
        /// </summary>
        /// <param name="SB">Where the code goes.</param>
        /// <param name="S">Specification of algebra.</param>
        /// <param name="cgd">Not used yet.</param>
        public override void Write(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd)
        {
            if (m_type is G25.SMV)
            {
                G25.SMV dstSmv = m_type as G25.SMV;

                if (m_declareVariable)
                {
                    SB.AppendLine("/* cannot yet assign and declare SMV type at the same time */");
                }

                RefGA.BasisBlade[] BL        = BasisBlade.GetNonConstBladeList(dstSmv);
                string[]           accessStr = CodeUtil.GetAccessStr(S, dstSmv, m_name, m_ptr);
                bool     writeZeros          = true;
                string[] valueStr            = CodeUtil.GetAssignmentStrings(S, m_floatType, m_mustCast, BL, m_value, writeZeros);

                // apply post operation (like "/ n2")
                ApplyPostOp(S, cgd, BL, valueStr);

                SB.AppendLine(CodeUtil.GenerateAssignmentCode(S, accessStr, valueStr, m_nbTabs, writeZeros));
            }
            else if (m_type is G25.FloatType)
            {
                // temp hack to override float type.
                G25.FloatType FT = this.m_floatType; // m_type as G25.FloatType;

                AppendTabs(SB);

                if (m_declareVariable)
                { // also declare the variable right here?
                    // output "/t type "
                    SB.Append(FT.type + " ");
                }

                // output name = ....;
                RefGA.BasisBlade[] BL = new RefGA.BasisBlade[1] {
                    RefGA.BasisBlade.ONE
                };
                String[] accessStr = new String[1] {
                    m_name
                };
                bool     writeZeros = true;
                String[] valueStr   = CodeUtil.GetAssignmentStrings(S, FT, m_mustCast, BL, m_value, writeZeros);

                // apply post operation (like "/ n2")
                ApplyPostOp(S, cgd, BL, valueStr);

                SB.AppendLine(CodeUtil.GenerateAssignmentCode(S, accessStr, valueStr, 0, writeZeros));
            }
            else
            {
                SB.AppendLine("/* to do: implement " + GetType().ToString() + " for type " + m_type.GetType().ToString() + " */");
            }
        }
Ejemplo n.º 12
0
 /// <summary>
 /// Returns the code to copy an array of 'nb' floats from 'srcPtrName' to 'dstPtrName'.
 /// </summary>
 public static string GetCopyCode(G25.Specification S, G25.FloatType FT, string srcPtrName, string dstPtrName, int nb)
 {
     if (nb <= Main.MAX_EXPLICIT_ZERO)
     {
         return(GetZeroCodePrefix(S, FT) + GetCopyFuncName(S) + "_" + nb + "(" + dstPtrName + ", " + srcPtrName + ");\n");
     }
     else
     {
         return(GetCopyCode(S, FT, srcPtrName, dstPtrName, nb.ToString()));
     }
 }
Ejemplo n.º 13
0
 /// <summary>
 /// Returns the code to set ptrName[0] to ptrName[nb-1] to 0.
 /// </summary>
 public static string GetSetToZeroCode(G25.Specification S, G25.FloatType FT, string ptrName, int nb)
 {
     if (nb <= Main.MAX_EXPLICIT_ZERO)
     {
         return(GetZeroCodePrefix(S, FT) + GetZeroFuncName(S) + "_" + nb + "(" + ptrName + ");\n");
     }
     else
     {
         return(GetSetToZeroCode(S, FT, ptrName, nb.ToString()));
     }
 }
Ejemplo n.º 14
0
        }                     // end of function WriteDualParts()

        /// <summary>
        /// Returns the code for dualization wrt to whole space using metric <c>M</c>.
        /// The code is composed of calls to functions generated by <c>WriteGmvDualParts()</c>.
        ///
        /// This function uses <c>cdg.m_gmvDualPartFuncNames</c>, but only to check whether a
        /// geometric product of some group with the pseudoscalar will get non-zero results in some
        /// other group.
        ///
        /// The returned code is only the body. The function declaration is not included.
        /// </summary>
        /// <param name="S">Specification of algebra (used for general multivector type, output language).</param>
        /// <param name="cgd">Used for <c>m_gmvDualPartFuncNames</c>.</param>
        /// <param name="FT">Floating point type.</param>
        /// <param name="M">The metric of the dual.</param>
        /// <param name="FAI">Info about function arguments</param>
        /// <param name="resultName">Name of variable where the result goes (in the generated code).</param>
        /// <param name="dual">When true, 'dual' is generated, otherwise, 'undual' is generated.</param>
        /// <returns>code for the requested product type.</returns>
        public static string GetDualCode(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT,
                                         G25.Metric M, G25.CG.Shared.FuncArgInfo[] FAI, string resultName, bool dual)
        {
            if (S.OutputCppOrC())
            {
                return(GetDualCodeCppOrC(S, cgd, FT, M, FAI, resultName, dual));
            }
            else
            {
                return(GetDualCodeCSharpOrJava(S, cgd, FT, M, FAI, resultName, dual));
            }
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Writes functions to set coordinates of the GMV
        /// </summary>
        /// <param name="S"></param>
        /// <param name="cgd">Results go here. Also intermediate data for code generation. Also contains plugins and cog.</param>
        /// <param name="FT"></param>
        /// <param name="SB"></param>
        public static void WriteSetCoord(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, StringBuilder SB)
        {
            G25.GMV gmv      = S.m_GMV;
            string  typeName = FT.GetMangledName(S, gmv.Name);

            for (int groupIdx = 0; groupIdx < gmv.NbGroups; groupIdx++)
            {
                for (int elementIdx = 0; elementIdx < gmv.Group(groupIdx).Length; elementIdx++)
                {
                    WriteSetCoordFunction(S, cgd, FT, SB, typeName, groupIdx, elementIdx, gmv.Group(groupIdx).Length, gmv.Group(groupIdx)[elementIdx]);
                }
            }
        }
Ejemplo n.º 16
0
        } // 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]));
            }
        }
Ejemplo n.º 17
0
        } // end of function BinaryScalarOpToLangString()

        public static string OpNameToLangString(G25.Specification S, G25.FloatType FT, string opName)
        {
            switch (S.m_outputLanguage)
            {
            case OUTPUT_LANGUAGE.C:
                if (FT.type == "float")
                {
                    return(m_floatOpsC[opName]);
                }
                else
                {
                    return(m_doubleOpsC[opName]);
                }

            case OUTPUT_LANGUAGE.CPP:
                if (FT.type == "float")
                {
                    return(m_floatOpsCpp[opName]);
                }
                else
                {
                    return(m_doubleOpsCpp[opName]);
                }

            case OUTPUT_LANGUAGE.CSHARP:
                if (FT.type == "float")
                {
                    return(m_floatOpsCSharp[opName]);
                }
                else
                {
                    return(m_doubleOpsCSharp[opName]);
                }

            case OUTPUT_LANGUAGE.JAVA:
                if (FT.type == "float")
                {
                    return(m_floatOpsJava[opName]);
                }
                else
                {
                    return(m_doubleOpsJava[opName]);
                }

            default:
                throw new Exception("G25.CG.Shared.BasisBlade.ScalarOpToLangString(): todo: language " + S.GetOutputLanguageString());
            }
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Writes functions to extract coordinates from the GMV
        /// </summary>
        /// <param name="S"></param>
        /// <param name="cgd">Results go here. Also intermediate data for code generation. Also contains plugins and cog.</param>
        /// <param name="FT"></param>
        /// <param name="SB"></param>
        public static void WriteGetCoord(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, StringBuilder SB)
        {
            G25.GMV gmv      = S.m_GMV;
            string  typeName = FT.GetMangledName(S, gmv.Name);

            for (int groupIdx = 0; groupIdx < gmv.NbGroups; groupIdx++)
            {
                for (int elementIdx = 0; elementIdx < gmv.Group(groupIdx).Length; elementIdx++)
                {
                    WriteGetCoordFunction(S, cgd, FT, SB, typeName, groupIdx, elementIdx, gmv.Group(groupIdx)[elementIdx]);
                }
            }

            SB.AppendLine("\t/// Returns array of compressed coordinates.");
            SB.AppendLine("\tinline const " + FT.type + " *getC() const { return m_c;}");
        }
Ejemplo n.º 19
0
        /// <summary>
        /// Writes a function to set an SMV struct to zero, for all floating point types.
        /// </summary>
        /// <param name="S">Used for basis vector names and output language.</param>
        /// <param name="cgd">Results go here. Also intermediate data for code generation. Also contains plugins and cog.</param>
        private static void WriteSetZero(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.SMV smv)
        {
            //if (smv.NbNonConstBasisBlade == 0) return;

            cgd.m_defSB.AppendLine("");

            string funcName = GMV.GetSetFuncName(S);
            bool   mustCast = false;

            string returnVarName = null;
            string dstName       = G25.CG.Shared.SmvUtil.THIS;
            bool   dstPtr        = false;

            bool staticFunc = false;

            G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd,
                                                            S.m_inlineSet, staticFunc, "void", returnVarName, funcName, null, null, FT, mustCast, smv, dstName, dstPtr, new RefGA.Multivector(0.0));
        } // end of WriteSetZero()
Ejemplo n.º 20
0
        /// <summary>
        /// Appends the non-mangled typenames of the type of all arguments to the name of 'F'.
        /// Also appends the float type.
        /// </summary>
        /// <param name="S">Specification (used for output language).</param>
        /// <param name="FT">Float type of function.</param>
        /// <param name="funcName">The function name.</param>
        /// <param name="typeNames">Typenames of function arguments. Some entries may be null.</param>
        /// <returns>new name.</returns>
        public static string AppendTypenameToFuncName(Specification S, G25.FloatType FT, string funcName, string[] typeNames)
        {
            StringBuilder SB = new StringBuilder(funcName);

            if (!funcName.Contains(G25.Specification.DONT_MANGLE)) // for the auto-dependency system to work, we should not mangle when this string is present!
            {
                foreach (string tn in typeNames)
                {
                    if (tn != null)
                    {
                        SB.Append("_");
                        SB.Append(tn);
                    }
                }
            }

            return(FT.GetMangledName(S, SB.ToString()));
        }
Ejemplo n.º 21
0
        private static string GetZeroCodePrefix(G25.Specification S, G25.FloatType FT)
        {
            switch (S.m_outputLanguage)
            {
            case OUTPUT_LANGUAGE.C:
                return(S.m_namespace + "_" + FT.type + "_");

            case OUTPUT_LANGUAGE.CPP:
                return(S.m_namespace + "::");

            case OUTPUT_LANGUAGE.CSHARP:
            case OUTPUT_LANGUAGE.JAVA:
                return(S.m_namespace + ".");

            default:
                return("GetZeroCodePrefix(): not implemented yet");
            }
        }
Ejemplo n.º 22
0
        } // end of WriteSetCoords()

        /// <summary>
        /// Writes a function to set an SMV struct to an array of specified coordinates, for all floating point types.
        /// </summary>
        /// <param name="S">Used for basis vector names and output language.</param>
        /// <param name="cgd">Intermediate data for code generation. Also contains plugins and cog.</param>
        public static void WriteSetArray(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.SMV smv)
        {
            //if (smv.NbNonConstBasisBlade == 0) return;

            cgd.m_defSB.AppendLine("");

            //string className = FT.GetMangledName(S, smv.Name);
            string funcName = GMV.GetSetFuncName(S);
            bool   mustCast = false;

            string[] argTypename = new string[2] {
                G25.CG.Shared.SmvUtil.COORDINATE_ORDER_ENUM, FT.type
            };
            string[] argName = new string[2] {
                "co", "A"
            };

            System.Collections.ArrayList L = new System.Collections.ArrayList();
            for (int i = 0; i < smv.NbNonConstBasisBlade; i++)
            {
                RefGA.BasisBlade B        = smv.NonConstBasisBlade(i);
                String           coordStr = argName[1] + "[" + i + "]";
                L.Add(new RefGA.BasisBlade(B.bitmap, B.scale, coordStr));
            }
            RefGA.Multivector mvValue = new RefGA.Multivector(L);

            G25.fgs F = new G25.fgs(funcName, funcName, "", argTypename, argName, new string[] { FT.type }, null, null, null); // null, null, null = metricName, comment, options
            F.InitArgumentPtrFromTypeNames(S);
            F.SetArgumentArr(1, true);                                                                                         // second argument is an array

            bool computeMultivectorValue = false;
            int  NB_ARGS = 2; // enum + one array of coordinates

            G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(S, F, NB_ARGS, FT, null, computeMultivectorValue);

            string dstName = G25.CG.Shared.SmvUtil.THIS;
            bool   dstPtr  = false;

            bool staticFunc = false;

            G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd,
                                                            S.m_inlineSet, staticFunc, "void", null, funcName, null, FAI, FT, mustCast, smv, dstName, dstPtr, mvValue);
        } // end of WriteSetArray()
Ejemplo n.º 23
0
        /// <summary>
        /// Writes a function to set an SMV class to specified coordinates, for all floating point types.
        /// </summary>
        /// <param name="S">Used for basis vector names and output language.</param>
        /// <param name="cgd">Intermediate data for code generation. Also contains plugins and cog.</param>
        public static void WriteSetCoords(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, G25.SMV smv)
        {
            //if (smv.NbNonConstBasisBlade == 0) return;

            cgd.m_defSB.AppendLine("");

            //string className = FT.GetMangledName(S, smv.Name);
            string funcName = GMV.GetSetFuncName(S);
            bool   mustCast = false;

            System.Collections.ArrayList L = new System.Collections.ArrayList();
            int NB_ARGS = 1 + smv.NbNonConstBasisBlade;

            string[] argTypename = new String[NB_ARGS];
            string[] argName     = new String[NB_ARGS];
            argTypename[0] = G25.CG.Shared.SmvUtil.COORDINATE_ORDER_ENUM;
            argName[0]     = "co";
            for (int i = 0; i < smv.NbNonConstBasisBlade; i++)
            {
                RefGA.BasisBlade B = smv.NonConstBasisBlade(i);
                argTypename[i + 1] = FT.type;
                string coordStr = "_" + smv.GetCoordLangID(i, S, COORD_STORAGE.VARIABLES);
                argName[i + 1] = coordStr;
                L.Add(new RefGA.BasisBlade(B.bitmap, B.scale, coordStr));
            }
            RefGA.Multivector mvValue = new RefGA.Multivector(L);


            G25.fgs F = new G25.fgs(funcName, funcName, "", argTypename, argName, new String[] { FT.type }, null, null, null); // null, null, null = metricName, comment, options
            F.InitArgumentPtrFromTypeNames(S);
            bool computeMultivectorValue = false;

            G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(S, F, NB_ARGS, FT, null, computeMultivectorValue);

            string dstName = G25.CG.Shared.SmvUtil.THIS;
            bool   dstPtr  = false;

            bool staticFunc = false;

            G25.CG.Shared.Functions.WriteAssignmentFunction(S, cgd,
                                                            S.m_inlineSet, staticFunc, "void", null, funcName, null, FAI, FT, mustCast, smv, dstName, dstPtr, mvValue);
        } // end of WriteSetCoords()
Ejemplo n.º 24
0
        } // 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));
                }
            }
        }
Ejemplo n.º 25
0
        /// <summary>
        /// Appends the non-mangled typenames of the type of all arguments to the <c>m_outputName</c> in <c>F</c>.
        /// Also appends the float type.
        /// </summary>
        /// <param name="S">Specification (used for output language).</param>
        /// <param name="FT">Float type of function.</param>
        /// <param name="F">The function (it is copied, but with changed name).</param>
        /// <param name="FAI">Info on function arguments.</param>
        /// <returns>a copy of <c>F</c> with a new name.</returns>
        public static G25.fgs AppendTypenameToFuncName(Specification S, G25.FloatType FT, G25.fgs F, G25.CG.Shared.FuncArgInfo[] FAI)
        {
            if (S.m_outputLanguage != OUTPUT_LANGUAGE.C)
            {
                return(new G25.fgs(F, F.OutputName));
            }
            else
            {
                string[] typeNames = new string[FAI.Length];
                for (int i = 0; i < FAI.Length; i++)
                {
                    if (DontAppendTypename(FAI[i].TypeName))
                    {
                        continue;
                    }

                    typeNames[i] = FAI[i].MangledTypeName;
                }

                return(new G25.fgs(F, AppendTypenameToFuncName(S, FT, F.OutputName, typeNames)));
            }
        }
Ejemplo n.º 26
0
        } // 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()
Ejemplo n.º 27
0
        } // 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);
        }
Ejemplo n.º 28
0
 /// <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;
 }
Ejemplo n.º 29
0
        } // end of GetAssignmentStrings()

        /// <summary>
        /// Used internally by ScalarToLangString().
        ///
        /// Emits on term (+ ....) of a blade value. Contains some optimizations
        /// to avoid stuff like <c>+-1.0</c>.
        /// </summary>
        protected static int EmitTerm(G25.Specification S, G25.FloatType FT, Object[] T, int tCnt, StringBuilder symResult)
        {
            // make stuff below a function
            bool plusEmitted = false;
            int  pCnt        = 0;              // number of non-null terms in 'T'

            for (int p = 0; p < T.Length; p++) // for each product ...*
            {
                if (T[p] != null)
                {
                    if ((!plusEmitted) && (tCnt > 0))
                    {
                        symResult.Append("+");
                        plusEmitted = true;
                    }
                    if ((pCnt > 0) && (symResult.Length > 0) && (!((symResult[symResult.Length - 1] == '-') || (symResult[symResult.Length - 1] == '+'))))
                    {
                        symResult.Append("*");
                    }

                    System.Object O = T[p];
                    if ((O is System.Double) ||
                        (O is System.Single) ||
                        (O is System.Int16) ||
                        (O is System.Int32) ||
                        (O is System.Int64)) // etc . . . (all number types)
                    {
                        double val = (double)O;
                        if ((val == -1.0) && (p == 0) && (T.Length > 1))
                        {                                                   // when multiplying with -1.0, output only a '-', IF the term is the first (p==0) and more terms follow (T.Length > 1)
                            if (symResult.Length > 0)
                            {                                               // when val = -1, output code which is better for humans, instead of -1.0 * ...
                                if (symResult[symResult.Length - 1] == '+') // change '+' to '-'
                                {
                                    symResult[symResult.Length - 1] = '-';
                                }
                                else
                                {
                                    symResult.Append("-");
                                }
                            }
                            else
                            {
                                symResult.Append("-");
                            }
                        }
                        else if ((val == 1.0) && (p == 0) && (T.Length > 1))
                        { // when multiplying with 1.0, output nothing IF the term is the first (p==0) and more terms follow (T.Length > 1)
                          // do nothing
                        }
                        else
                        {
                            symResult.Append(FT.DoubleToString(S, (double)O));
                        }
                    }
                    else if (O is UnaryScalarOp)
                    {
                        UnaryScalarOp USO = (UnaryScalarOp)O;
                        symResult.Append(UnaryScalarOpToLangString(S, FT, USO));
                    }
                    else if (O is BinaryScalarOp)
                    {
                        BinaryScalarOp BSO = (BinaryScalarOp)O;
                        symResult.Append(BinaryScalarOpToLangString(S, FT, BSO));
                    }
                    else if (O is RefGA.BasisBlade)
                    {
                        symResult.Append(ScalarToLangString(S, FT, (RefGA.BasisBlade)O));
                    }
                    else if (O is RefGA.Multivector)
                    {
                        RefGA.Multivector mv   = (RefGA.Multivector)O;
                        StringBuilder     mvSB = new StringBuilder();
                        mvSB.Append("(");
                        bool first = true;
                        foreach (RefGA.BasisBlade B in mv.BasisBlades)
                        {
                            if (!first)
                            {
                                mvSB.Append(" + ");
                            }
                            first = false;
                            mvSB.Append(ScalarToLangString(S, FT, B));
                        }

                        mvSB.Append(")");

                        symResult.Append(mvSB);
                    }
                    else
                    {
                        symResult.Append(O.ToString());
                    }

                    pCnt++;
                }
            }
            return(pCnt);
        }
Ejemplo n.º 30
0
        private static string GetComment(Specification S, bool declOnly, G25.fgs FGS, G25.Operator op, G25.FloatType FT, bool assign)
        {
            StringBuilder SB = new StringBuilder();

            if ((S.OutputCpp()) && op.IsUnaryInPlace())
            {
                if (op.IsPrefix)
                {
                    SB.Append("returns (" + FGS.ArgumentVariableNames[0] + " = " + FGS.OutputName + "(" + FGS.ArgumentVariableNames[0] + "))");
                }
                else
                {
                    SB.Append("returns input value of " + FGS.ArgumentVariableNames[0] + ", but sets " + FGS.ArgumentVariableNames[0] + " to " + FGS.OutputName + "(" + FGS.ArgumentVariableNames[0] + ")");
                }
            }
            else if (assign)
            {
                SB.Append("returns (" + FGS.ArgumentVariableNames[0] + " = " + FGS.OutputName + "(" + FGS.ArgumentVariableNames[0]);
                SB.Append(", " + FGS.ArgumentVariableNames[1]);
                SB.Append("))");
            }
            else
            {
                SB.Append("returns " + FGS.OutputName + "(" + FGS.ArgumentVariableNames[0]);
                if (op.IsBinary())
                {
                    SB.Append(", " + FGS.ArgumentVariableNames[1]);
                }
                SB.Append(")");
            }

            return(SB.ToString());
        }
Ejemplo n.º 31
0
        /// <summary>
        /// Converts a scalar basis blade (with optional symbolic part) to a string in the output language of <c>S</c>.
        ///
        /// Some effort is made to output code which is close to that a human would write.
        /// </summary>
        /// <param name="S">Specification of algebra, used for output language, basis vector names, etc.</param>
        /// <param name="FT">Floating point type of output.</param>
        /// <param name="B">The basis blade.</param>
        /// <returns>String code representation of 'B'.</returns>
        public static string ScalarToLangString(G25.Specification S, G25.FloatType FT, RefGA.BasisBlade B)
        {
            string symScaleStr = "";

            { // convert symbolic part
                if (B.symScale != null)
                {
                    // symbolic scalar string goes in  symResult
                    System.Text.StringBuilder symResult = new System.Text.StringBuilder();
                    int tCnt = 0;
                    for (int t = 0; t < B.symScale.Length; t++)       // for each term ...*...*...+
                    {
                        Object[] T = (Object[])B.symScale[t].Clone(); // clone 'T' because IsolateInverses() might alter it!
                        if (T != null)                                // if term is not null
                        {
                            // first find all scalarop inverses
                            // turn those into a new term, but without inverses?
                            Object[] TI = IsolateInverses(T);

                            // emit 'T'
                            int pCnt = EmitTerm(S, FT, T, tCnt, symResult);

                            if (TI != null)  // do we have to divide by a number of terms?
                            {
                                // emit '/(TI)'
                                symResult.Append("/(");
                                EmitTerm(S, FT, TI, 0, symResult);
                                symResult.Append(")");
                            }

                            if (pCnt > 0)
                            {
                                tCnt++;           // only increment number of terms when T was not empty
                            }
                        }
                    }

                    if (tCnt > 0)
                    {
                        symScaleStr = ((tCnt > 1) ? "(" : "") + symResult + ((tCnt > 1) ? ")" : "");
                    }
                }
            } // end of symbolic part

            // special cases when numerical scale is exactly +- 1
            if (B.scale == 1.0)
            {
                if (symScaleStr.Length > 0)
                {
                    return(symScaleStr);
                }
                else
                {
                    return(FT.DoubleToString(S, 1.0));
                }
            }
            else if (B.scale == -1.0)
            {
                if (symScaleStr.Length > 0)
                {
                    return("-" + symScaleStr);
                }
                else
                {
                    return(FT.DoubleToString(S, -1.0));
                }
            }
            else
            {
                // get numerical part
                string numScaleStr = FT.DoubleToString(S, B.scale);

                // merge symbolic and numerical
                if (symScaleStr.Length > 0)
                {
                    numScaleStr = numScaleStr + "*" + symScaleStr;
                }

                // done
                return(numScaleStr);
            }
        } // end of function ScalarToLangString