Example #1
0
        /// <summary>
        /// Returns the name of a generated function (for example <c>gp_mv_mv</c>).
        /// If the function is not found, a DependencyException is thrown.
        ///
        /// The function is found by looking through all G25.FGS in the specification.
        /// </summary>
        /// <param name="S">The spec.</param>
        /// <param name="functionName">Basic name of the function to be found.</param>
        /// <param name="argumentTypes">Names of the arguments types (not mangled).</param>
        /// <param name="returnTypeName">Name of the return type (can be null or "" for default return type).</param>
        /// <param name="FT">Floating point type.</param>
        /// <param name="metricName">(optional, can be null for don't care)</param>
        /// <returns>The mangled name of the function.</returns>
        public static string GetFunctionName(Specification S, string functionName, string[] argumentTypes, string returnTypeName, G25.FloatType FT, string metricName)
        {
            fgs F = S.FindFunctionEx(functionName, argumentTypes, returnTypeName, new String[] { FT.type }, metricName);

            if (F == null) // error: function not found
            {
                string exStr = "G25.CG.Shared.Util.GetFunctionName(): cannot find function " + functionName + " with arguments (";
                for (int i = 0; i < argumentTypes.Length; i++)
                {
                    if (i > 0)
                    {
                        exStr = exStr + ", ";
                    }
                    exStr = exStr + argumentTypes[i];
                }
                exStr = exStr + ") and using floating point type " + FT.type;
                if (metricName != null)
                {
                    exStr = exStr + " and using metric " + metricName;
                }
                throw new DependencyException(exStr);
            }
            else
            {
                argumentTypes = F.ArgumentTypeNames;


                string mangledFuncName = F.OutputName;
                if (S.OutputC())
                {
                    // add mangled argument types to function name
                    string[] mangledArgumentTypes = new string[argumentTypes.Length];
                    for (int i = 0; i < argumentTypes.Length; i++)
                    {
                        if (Util.DontAppendTypename(argumentTypes[i]))
                        {
                            continue;
                        }

                        mangledArgumentTypes[i] = (S.IsFloatType(argumentTypes[i])) ? FT.type : FT.GetMangledName(S, argumentTypes[i]);
                    }
                    mangledFuncName = Util.AppendTypenameToFuncName(S, FT, F.OutputName, mangledArgumentTypes);
                    //mangledFuncName = FT.GetMangledName(S, mangledFuncName);
                }
                else if (argumentTypes.Length == 0)
                {
                    // test to apply mangling when no arguments are present.
                    mangledFuncName = FT.GetMangledName(S, mangledFuncName);
                }

                return(mangledFuncName);
            }
        } // end of GetFunctionName()
Example #2
0
        public static void AddDefaultGmvConverters(Specification S)
        {
            // get a 'set' of SMVs for which converters to GMV are present
            Dictionary <string, fgs> converterPresent = new Dictionary <string, fgs>();

            foreach (fgs F in S.m_functions)
            {
                if (F.IsConverter(S))
                {
                    if (F.GetArgumentTypeName(0, null) == S.m_GMV.Name)
                    {
                        converterPresent.Add(F.Name.Substring(1), F);
                    }
                }
            }

            // get array of float type names, for use below
            string[] floatNames = new string[S.m_floatTypes.Count];
            for (int i = 0; i < S.m_floatTypes.Count; i++)
            {
                floatNames[i] = S.m_floatTypes[i].type;
            }


            // loop over all SMVs, if no converter to GMV is present, add it
            foreach (G25.SMV smv in S.m_SMV)
            {
                if (converterPresent.ContainsKey(smv.Name))
                {
                    continue;
                }

                string   outputName                 = null;
                string   returnTypeName             = null;
                string[] argumentTypeNames          = new string[] { S.m_GMV.Name };
                string[] argumentVariableNames      = null;
                string   metricName                 = null;
                Dictionary <string, string> options = null;
                fgs F = new fgs("_" + smv.Name, outputName, returnTypeName,
                                argumentTypeNames, argumentVariableNames,
                                floatNames, metricName, COMMENT, options);
                S.m_functions.Add(F);
            }
        }
Example #3
0
        /// <summary>
        /// This function checks the dependencies for the _testing_ code of this function. If dependencies are
        /// missing, the function adds the required functions (this is done simply by asking for them . . .).
        /// </summary>
        public override void CheckTestingDepencies()
        {
            //bool returnTrueName = true;
            foreach (string floatName in m_fgs.FloatNames)
            {
                FloatType FT = m_specification.GetFloatType(floatName);

                m_randomScalarFuncName[FT.type] = G25.CG.Shared.Dependencies.GetDependency(m_specification, m_cgd, "random_" + FT.type, new String[0], FT.type, FT, null);
                string[] cgaPointArgs = new String[m_specification.m_dimension - 2];
                for (int i = 0; i < cgaPointArgs.Length; i++)
                {
                    cgaPointArgs[i] = FT.type;
                }

                string cgaPointFuncName      = "cgaPoint";
                string defaultReturnTypeName = null;
                m_cgaPointFuncName[FT.type] = G25.CG.Shared.Dependencies.GetDependency(m_specification, m_cgd, cgaPointFuncName, cgaPointArgs, defaultReturnTypeName, FT, null);
                fgs cgaPointFGS = m_specification.FindFunctionEx(cgaPointFuncName, cgaPointArgs, null, new String[] { FT.type }, null);
                m_cgaPointTypeName[FT.type] = cgaPointFGS.ReturnTypeName;
            }
        }
Example #4
0
        public static void AddDefaultGmvConverters(Specification S)
        {
            // get a 'set' of SMVs for which converters to GMV are present
            Dictionary<string, fgs> converterPresent = new Dictionary<string, fgs>();
            foreach (fgs F in S.m_functions)
            {
                if (F.IsConverter(S))
                {
                    if (F.GetArgumentTypeName(0, null) == S.m_GMV.Name)
                    {
                        converterPresent.Add(F.Name.Substring(1), F);
                    }
                }
            }

            // get array of float type names, for use below
            string[] floatNames = new string[S.m_floatTypes.Count];
            for (int i = 0; i < S.m_floatTypes.Count; i++)
                floatNames[i] = S.m_floatTypes[i].type;

            // loop over all SMVs, if no converter to GMV is present, add it
            foreach (G25.SMV smv in S.m_SMV)
            {
                if (converterPresent.ContainsKey(smv.Name)) continue;

                string outputName = null;
                string returnTypeName = null;
                string[] argumentTypeNames = new string[] {S.m_GMV.Name};
                string[] argumentVariableNames = null;
                string metricName = null;
                Dictionary<string, string> options = null;
                fgs F = new fgs("_" + smv.Name, outputName, returnTypeName,
                    argumentTypeNames, argumentVariableNames,
                    floatNames, metricName, COMMENT, options);
                S.m_functions.Add(F);

            }
        }
Example #5
0
        /// <summary>
        /// Writes the 'explicit' declaration/definitions of 'F' to StringBuffer 'SB', taking into account parameters specified in specification 'S'.
        ///
        /// This function is called by the non-explicit version of the function.
        /// </summary>
        public void WriteExFunction(FloatType FT, string exFuncName)
        {
            G25.SMV smv = m_specification.GetSMV(m_SMVname);

            string randFuncCall = FT.DoubleToString(m_specification, -1.0) + " + " + FT.DoubleToString(m_specification, 2.0) + " * " + m_randomScalarFunc[FT.type] + "()";

            // construct a explicit FGS
            string[] exArgumentTypeNames = new string[] { FT.type, FT.type, FT.type };
            string[] exVariableNames     = { m_fgs.ArgumentVariableNames[0], MINIMUM_NORM, LARGEST_COORDINATE };
            fgs      exFgs = new fgs(m_fgs.Name, m_fgs.OutputName, m_fgs.ReturnTypeName, exArgumentTypeNames, exVariableNames, m_fgs.FloatNames, m_fgs.MetricName, m_fgs.Comment, m_fgs.Options);

            exFgs.InitArgumentPtrFromTypeNames(m_specification);

            bool computeMultivectorValue = false;
            int  nbArgs = 3;

            G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, exFgs, nbArgs, FT, FT.type, computeMultivectorValue);

            // because of lack of overloading, function names include names of argument types
            //G25.fgs CF = G25.CG.Shared.Util.AppendTypenameToFuncName(m_specification, FT, exFgs, FAI);
            G25.fgs CF = new G25.fgs(exFgs, exFuncName);
            //string exFuncName = funcName;

            // setup code to recursively call exFuncName
            string exFuncCall = "";

            {
                StringBuilder exFuncCallSB = new StringBuilder();
                if (!m_specification.OutputC())
                {
                    exFuncCallSB.Append("return ");
                }

                exFuncCallSB.Append(exFuncName);
                exFuncCallSB.Append("(");
                if (m_specification.OutputC())
                {
                    exFuncCallSB.Append(fgs.RETURN_ARG_NAME);
                    exFuncCallSB.Append(", ");
                }
                for (int i = 0; i < exVariableNames.Length; i++)
                {
                    if (i > 0)
                    {
                        exFuncCallSB.Append(", ");
                    }
                    exFuncCallSB.Append(exVariableNames[i]);
                }
                exFuncCallSB.AppendLine(");");
                if (m_specification.OutputC())
                {
                    exFuncCallSB.AppendLine("return;");
                }
                exFuncCall = exFuncCallSB.ToString();
            }

            // generate a random SMV:
            RefGA.Multivector randomSMV = null;

            // get highest grade and bitmap of
            int  hg       = smv.HighestGrade();      // what is the highest non-zero grade of the type?
            uint bvBitmap = smv.BasisVectorBitmap(); // which basis vectors are used in the type?

            // setup random value to be returned
            if (InitWithRandomCoordinates(m_specification, smv))
            {
                // set all coordinates to random values
                randomSMV = RefGA.Multivector.ZERO;
                for (int b = 0; b < smv.NbNonConstBasisBlade; b++)
                {
                    randomSMV = RefGA.Multivector.Add(randomSMV,
                                                      RefGA.Multivector.gp(new RefGA.Multivector(smv.NonConstBasisBlade(b)),
                                                                           new RefGA.Multivector("r" + smv.NonConstBasisBlade(b).ToLangString(m_specification.m_basisVectorNames))));
                }
            }
            else
            {
                // set to geometric product of random vectors
                randomSMV = RefGA.Multivector.ONE;
                RefGA.Multivector  randomVector;
                RefGA.BasisBlade[] B = new RefGA.BasisBlade[(int)RefGA.Bits.BitCount(bvBitmap)];
                for (int g = 0; g < hg; g++)
                {
                    int cnt = 0;
                    for (int v = 0; v < m_specification.m_dimension; v++)
                    {
                        if ((bvBitmap & (uint)(1 << v)) != 0)
                        {
                            B[cnt] = new RefGA.BasisBlade((uint)(1 << v), 1.0, "r" + g + "_" + m_specification.m_basisVectorNames[v]);
                            cnt++;
                        }
                    }
                    randomVector = new RefGA.Multivector(B);
                    randomSMV    = RefGA.Multivector.gp(randomSMV, randomVector, m_G25M.m_metric);
                }

                // round value if required by metric
                if (m_G25M.m_round)
                {
                    randomSMV = randomSMV.Round(1e-14);
                }
            }

            // setup instructions
            System.Collections.Generic.List <G25.CG.Shared.Instruction> I = new System.Collections.Generic.List <G25.CG.Shared.Instruction>();
            {
                int nbTabs = 1;

                if (!smv.IsConstant())
                {
                    string smvTypeName = FT.GetMangledName(m_specification, m_SMVname);

                    // SMV tmp;
                    // double n, mul, lc;
                    if (m_specification.OutputCppOrC())
                    {
                        I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, smvTypeName + " tmp;"));
                    }
                    else
                    {
                        I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, smvTypeName + " tmp = new " + smvTypeName + "();"));
                    }
                    I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, FT.type + " n, mul, lc;"));
                    I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, CodeUtil.GetBoolType(m_specification) + " nullBlade;"));

                    // double rCoord = randomValue(), ....;
                    StringBuilder randSB = new StringBuilder();
                    randSB.Append(FT.type);
                    randSB.Append(" ");
                    if (InitWithRandomCoordinates(m_specification, smv))
                    { // random coordinates
                        for (int b = 0; b < smv.NbNonConstBasisBlade; b++)
                        {
                            if (b > 0)
                            {
                                randSB.Append(", ");
                            }
                            randSB.Append("r" + smv.NonConstBasisBlade(b).ToLangString(m_specification.m_basisVectorNames));
                            randSB.Append(" = ");
                            randSB.Append(randFuncCall);
                        }
                    }
                    else
                    { // random vectors
                        bool first = true;
                        for (int g = 0; g < hg; g++)
                        {
                            for (int v = 0; v < m_specification.m_dimension; v++)
                            {
                                if (!first)
                                {
                                    randSB.Append(", ");
                                }
                                first = false;
                                if ((g > 0) && (v == 0))
                                {
                                    randSB.AppendLine(""); // newline
                                    randSB.Append("\t\t");
                                }
                                randSB.Append("r" + g + "_" + m_specification.m_basisVectorNames[v]);
                                randSB.Append(" = ");
                                randSB.Append(randFuncCall);
                            }
                        }
                    }
                    randSB.Append(";");
                    I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, randSB.ToString()));


                    // SMV tmp = random;
                    bool mustCast      = false;
                    bool randomPtr     = false;
                    bool declareRandom = false;
                    I.Add(new G25.CG.Shared.AssignInstruction(nbTabs, smv, FT, mustCast, randomSMV, "tmp", randomPtr, declareRandom));

                    // n = norm_ret_scalar(tmp);
                    string emp = (m_specification.OutputC()) ? "&" : "";
                    I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, "n = " + m_normFunc[FT.type] + "(" + emp + "tmp);"));

                    // lc = largestCoordinate(tmp);
                    if (m_specification.OutputC())
                    {
                        I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, "lc = " + smvTypeName + "_largestCoordinate(&tmp);"));
                    }
                    else
                    {
                        string lcStr = "largestCoordinate";
                        if (m_specification.OutputCSharp())
                        {
                            lcStr = "LargestCoordinate";
                        }
                        I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, "lc = tmp." + lcStr + "();"));
                    }

                    // null = (n == 0) && (lc ! 0)
                    if ((m_smvType.MvType == SMV.MULTIVECTOR_TYPE.ROTOR) || (m_smvType.MvType == SMV.MULTIVECTOR_TYPE.VERSOR))
                    {
                        I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, "nullBlade = " + (m_specification.OutputC() ? "0" : "false") + ";"));
                    }
                    else
                    {
                        I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, "nullBlade = ((n == " + FT.DoubleToString(m_specification, 0.0) + ") && (lc != " + FT.DoubleToString(m_specification, 0.0) + "));"));
                    }


                    // test minimumNorm
                    I.Add(new CommentInstruction(nbTabs, "Recurse if generated random value has a norm below user-supplied limit, unless this is a null blade"));
                    I.Add(new G25.CG.Shared.IfElseInstruction(nbTabs, "(n < " + exVariableNames[1] + ") && (!nullBlade)",
                                                              new List <Instruction>()
                    {
                        new G25.CG.Shared.VerbatimCodeInstruction(nbTabs + 1, exFuncCall)
                    },                                                                    // if instructions
                                                              new List <Instruction>())); // else instructions

                    // compute multiplier
                    string lcCondition = "(lc * " + CodeUtil.OpNameToLangString(m_specification, FT, "abs") + "(mul)) > largestCoordinate ";
                    I.Add(new CommentInstruction(nbTabs, "Compute multiplier"));
                    I.Add(new G25.CG.Shared.IfElseInstruction(nbTabs, "n < " + FT.DoubleToString(m_specification, 0.0001),
                                                              new List <Instruction>()
                    {
                        new G25.CG.Shared.VerbatimCodeInstruction(nbTabs + 1, "mul = " + FT.DoubleToString(m_specification, 1.0) + ";")
                    },                                                                 // if instructions
                                                              new List <Instruction>() // else instructions
                    {
                        new G25.CG.Shared.VerbatimCodeInstruction(nbTabs + 1, "mul = " + exFgs.ArgumentVariableNames[0] + " * (" + randFuncCall + ") / n;"),
                        new CommentInstruction(nbTabs + 1, "Test largest coordinate"),
                        new G25.CG.Shared.IfElseInstruction(nbTabs + 1, lcCondition,
                                                            new List <Instruction>()
                        {
                            new G25.CG.Shared.VerbatimCodeInstruction(nbTabs + 2, exFuncCall)
                        },                                                                                                      // if instructions
                                                            new List <Instruction>())
                    }));

                    // test largest coordinate
                    //I.Add(new CommentInstruction(nbTabs, "Test largest coordinate"));
                    //I.Add(new G25.CG.Shared.IfElseInstruction(nbTabs, lcCondition,
                    //   new List<Instruction>() { new G25.CG.Shared.VerbatimCodeInstruction(nbTabs + 1, exFuncCall) },  // if instructions
                    //    new List<Instruction>())); // else instructions

                    // return tmp*mul;
                    I.Add(new CommentInstruction(nbTabs, "Apply multiplier, return"));
                    RefGA.Multivector tmpValue    = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(m_specification, smv, "tmp", false);
                    RefGA.Multivector returnValue = RefGA.Multivector.gp(tmpValue, new RefGA.Multivector("mul"));
                    I.Add(new G25.CG.Shared.ReturnInstruction(nbTabs, smv, FT, mustCast, returnValue));
                } // end of '!IsConstant()'?
                else
                {
                    // the user wants a 'random' constant: simply return the constant itself.
                    RefGA.Multivector returnValue = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(m_specification, smv, "tmp", false);
                    bool mustCast = false;
                    I.Add(new G25.CG.Shared.ReturnInstruction(nbTabs, smv, FT, mustCast, returnValue));
                }
            }

            // because of lack of overloading, function names include names of argument types
            //G25.fgs CF = G25.CG.Shared.Util.AppendTypenameToFuncName(m_specification, FT, exFgs, FAI);

            // generate comment
            Comment comment = new Comment(exFgs.AddUserComment("Returns random " + m_SMVname + " with a scale in the interval [0, scale)"));

            bool staticFunc = Functions.OutputStaticFunctions(m_specification);

            G25.CG.Shared.Functions.WriteFunction(m_specification, m_cgd, CF, m_specification.m_inlineFunctions, staticFunc, exFuncName, FAI, I, comment);
        } // end of WriteExFunction
Example #6
0
        /// <summary>
        /// Writes the 'explicit' declaration/definitions of 'F' to StringBuffer 'SB', taking into account parameters specified in specification 'S'.
        /// 
        /// This function is called by the non-explicit version of the function.
        /// </summary>
        public void WriteExFunction(FloatType FT, string exFuncName)
        {
            G25.SMV smv = m_specification.GetSMV(m_SMVname);

            string randFuncCall = FT.DoubleToString(m_specification, -1.0) + " + " + FT.DoubleToString(m_specification, 2.0) + " * " + m_randomScalarFunc[FT.type] + "()";

            // construct a explicit FGS
            string[] exArgumentTypeNames = new string[] { FT.type, FT.type, FT.type };
            string[] exVariableNames = { m_fgs.ArgumentVariableNames[0], MINIMUM_NORM, LARGEST_COORDINATE };
            fgs exFgs = new fgs(m_fgs.Name, m_fgs.OutputName, m_fgs.ReturnTypeName, exArgumentTypeNames, exVariableNames, m_fgs.FloatNames, m_fgs.MetricName, m_fgs.Comment, m_fgs.Options);
            exFgs.InitArgumentPtrFromTypeNames(m_specification);

            bool computeMultivectorValue = false;
            int nbArgs = 3;
            G25.CG.Shared.FuncArgInfo[] FAI = G25.CG.Shared.FuncArgInfo.GetAllFuncArgInfo(m_specification, exFgs, nbArgs, FT, FT.type, computeMultivectorValue);

            // because of lack of overloading, function names include names of argument types
            //G25.fgs CF = G25.CG.Shared.Util.AppendTypenameToFuncName(m_specification, FT, exFgs, FAI);
            G25.fgs CF = new G25.fgs(exFgs, exFuncName);
            //string exFuncName = funcName;

            // setup code to recursively call exFuncName
            string exFuncCall = "";
            {
                StringBuilder exFuncCallSB = new StringBuilder();
                if (!m_specification.OutputC())
                    exFuncCallSB.Append("return ");

                exFuncCallSB.Append(exFuncName);
                exFuncCallSB.Append("(");
                if (m_specification.OutputC())
                {
                    exFuncCallSB.Append(fgs.RETURN_ARG_NAME);
                    exFuncCallSB.Append(", ");
                }
                for (int i = 0; i < exVariableNames.Length; i++)
                {
                    if (i > 0) exFuncCallSB.Append(", ");
                    exFuncCallSB.Append(exVariableNames[i]);
                }
                exFuncCallSB.AppendLine(");");
                if (m_specification.OutputC())
                {
                    exFuncCallSB.AppendLine("return;");
                }
                exFuncCall = exFuncCallSB.ToString();
            }

            // generate a random SMV:
            RefGA.Multivector randomSMV = null;

            // get highest grade and bitmap of
            int hg = smv.HighestGrade(); // what is the highest non-zero grade of the type?
            uint bvBitmap = smv.BasisVectorBitmap(); // which basis vectors are used in the type?

            // setup random value to be returned
            if (InitWithRandomCoordinates(m_specification, smv))
            {
                // set all coordinates to random values
                randomSMV = RefGA.Multivector.ZERO;
                for (int b = 0; b < smv.NbNonConstBasisBlade; b++)
                {
                    randomSMV = RefGA.Multivector.Add(randomSMV,
                        RefGA.Multivector.gp(new RefGA.Multivector(smv.NonConstBasisBlade(b)),
                        new RefGA.Multivector("r" + smv.NonConstBasisBlade(b).ToLangString(m_specification.m_basisVectorNames))));
                }
            }
            else
            {
                // set to geometric product of random vectors
                randomSMV = RefGA.Multivector.ONE;
                RefGA.Multivector randomVector;
                RefGA.BasisBlade[] B = new RefGA.BasisBlade[(int)RefGA.Bits.BitCount(bvBitmap)];
                for (int g = 0; g < hg; g++)
                {
                    int cnt = 0;
                    for (int v = 0; v < m_specification.m_dimension; v++)
                    {
                        if ((bvBitmap & (uint)(1 << v)) != 0)
                        {
                            B[cnt] = new RefGA.BasisBlade((uint)(1 << v), 1.0, "r" + g + "_" + m_specification.m_basisVectorNames[v]);
                            cnt++;
                        }
                    }
                    randomVector = new RefGA.Multivector(B);
                    randomSMV = RefGA.Multivector.gp(randomSMV, randomVector, m_G25M.m_metric);
                }

                // round value if required by metric
                if (m_G25M.m_round) randomSMV = randomSMV.Round(1e-14);
            }

            // setup instructions
            System.Collections.Generic.List<G25.CG.Shared.Instruction> I = new System.Collections.Generic.List<G25.CG.Shared.Instruction>();
            {
                int nbTabs = 1;

                if (!smv.IsConstant())
                {
                    string smvTypeName = FT.GetMangledName(m_specification, m_SMVname);

                    // SMV tmp;
                    // double n, mul, lc;
                    if (m_specification.OutputCppOrC())
                        I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, smvTypeName + " tmp;"));
                    else I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, smvTypeName + " tmp = new " + smvTypeName  + "();"));
                    I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, FT.type + " n, mul, lc;"));
                    I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, CodeUtil.GetBoolType(m_specification) + " nullBlade;"));

                    // double rCoord = randomValue(), ....;
                    StringBuilder randSB = new StringBuilder();
                    randSB.Append(FT.type);
                    randSB.Append(" ");
                    if (InitWithRandomCoordinates(m_specification, smv))
                    { // random coordinates
                        for (int b = 0; b < smv.NbNonConstBasisBlade; b++)
                        {
                            if (b > 0) randSB.Append(", ");
                            randSB.Append("r" + smv.NonConstBasisBlade(b).ToLangString(m_specification.m_basisVectorNames));
                            randSB.Append(" = ");
                            randSB.Append(randFuncCall);
                        }
                    }
                    else
                    { // random vectors
                        bool first = true;
                        for (int g = 0; g < hg; g++)
                        {
                            for (int v = 0; v < m_specification.m_dimension; v++)
                            {
                                if (!first) randSB.Append(", "); first = false;
                                if ((g > 0) && (v == 0))
                                {
                                    randSB.AppendLine(""); // newline
                                    randSB.Append("\t\t");
                                }
                                randSB.Append("r" + g + "_" + m_specification.m_basisVectorNames[v]);
                                randSB.Append(" = ");
                                randSB.Append(randFuncCall);
                            }
                        }
                    }
                    randSB.Append(";");
                    I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, randSB.ToString()));

                    // SMV tmp = random;
                    bool mustCast = false;
                    bool randomPtr = false;
                    bool declareRandom = false;
                    I.Add(new G25.CG.Shared.AssignInstruction(nbTabs, smv, FT, mustCast, randomSMV, "tmp", randomPtr, declareRandom));

                    // n = norm_ret_scalar(tmp);
                    string emp = (m_specification.OutputC()) ? "&" : "";
                    I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, "n = " + m_normFunc[FT.type] + "(" + emp + "tmp);"));

                    // lc = largestCoordinate(tmp);
                    if (m_specification.OutputC())
                    {
                        I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, "lc = " + smvTypeName + "_largestCoordinate(&tmp);"));
                    }
                    else
                    {
                        string lcStr = "largestCoordinate";
                        if (m_specification.OutputCSharp()) lcStr = "LargestCoordinate";
                        I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, "lc = tmp." + lcStr + "();"));
                    }

                    // null = (n == 0) && (lc ! 0)
                    if ((m_smvType.MvType == SMV.MULTIVECTOR_TYPE.ROTOR) || (m_smvType.MvType == SMV.MULTIVECTOR_TYPE.VERSOR))
                        I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, "nullBlade = " + (m_specification.OutputC() ? "0" : "false") + ";"));
                    else I.Add(new G25.CG.Shared.VerbatimCodeInstruction(nbTabs, "nullBlade = ((n == " + FT.DoubleToString(m_specification, 0.0) + ") && (lc != " + FT.DoubleToString(m_specification, 0.0) + "));"));

                    // test minimumNorm
                    I.Add(new CommentInstruction(nbTabs, "Recurse if generated random value has a norm below user-supplied limit, unless this is a null blade"));
                    I.Add(new G25.CG.Shared.IfElseInstruction(nbTabs, "(n < " + exVariableNames[1] + ") && (!nullBlade)",
                        new List<Instruction>() {new G25.CG.Shared.VerbatimCodeInstruction(nbTabs + 1, exFuncCall)},  // if instructions
                        new List<Instruction>())); // else instructions

                    // compute multiplier
                    string lcCondition = "(lc * " + CodeUtil.OpNameToLangString(m_specification, FT, "abs") + "(mul)) > largestCoordinate ";
                    I.Add(new CommentInstruction(nbTabs, "Compute multiplier"));
                    I.Add(new G25.CG.Shared.IfElseInstruction(nbTabs, "n < " + FT.DoubleToString(m_specification, 0.0001),
                        new List<Instruction>() { new G25.CG.Shared.VerbatimCodeInstruction(nbTabs + 1, "mul = " + FT.DoubleToString(m_specification, 1.0) + ";") }, // if instructions
                        new List<Instruction>() { // else instructions
                            new G25.CG.Shared.VerbatimCodeInstruction(nbTabs + 1, "mul = " + exFgs.ArgumentVariableNames[0] + " * (" + randFuncCall + ") / n;"),
                            new CommentInstruction(nbTabs+1, "Test largest coordinate"),
                            new G25.CG.Shared.IfElseInstruction(nbTabs+1, lcCondition,
                                new List<Instruction>() { new G25.CG.Shared.VerbatimCodeInstruction(nbTabs + 2, exFuncCall) },  // if instructions
                                new List<Instruction>())
                        }));

                    // test largest coordinate
                    //I.Add(new CommentInstruction(nbTabs, "Test largest coordinate"));
                    //I.Add(new G25.CG.Shared.IfElseInstruction(nbTabs, lcCondition,
                    //   new List<Instruction>() { new G25.CG.Shared.VerbatimCodeInstruction(nbTabs + 1, exFuncCall) },  // if instructions
                    //    new List<Instruction>())); // else instructions

                    // return tmp*mul;
                    I.Add(new CommentInstruction(nbTabs, "Apply multiplier, return"));
                    RefGA.Multivector tmpValue = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(m_specification, smv, "tmp", false);
                    RefGA.Multivector returnValue = RefGA.Multivector.gp(tmpValue, new RefGA.Multivector("mul"));
                    I.Add(new G25.CG.Shared.ReturnInstruction(nbTabs, smv, FT, mustCast, returnValue));
                } // end of '!IsConstant()'?
                else
                {
                    // the user wants a 'random' constant: simply return the constant itself.
                    RefGA.Multivector returnValue = G25.CG.Shared.Symbolic.SMVtoSymbolicMultivector(m_specification, smv, "tmp", false);
                    bool mustCast = false;
                    I.Add(new G25.CG.Shared.ReturnInstruction(nbTabs, smv, FT, mustCast, returnValue));
                }

            }

            // because of lack of overloading, function names include names of argument types
            //G25.fgs CF = G25.CG.Shared.Util.AppendTypenameToFuncName(m_specification, FT, exFgs, FAI);

            // generate comment
            Comment comment = new Comment(exFgs.AddUserComment("Returns random " + m_SMVname + " with a scale in the interval [0, scale)"));

            bool staticFunc = Functions.OutputStaticFunctions(m_specification);
            G25.CG.Shared.Functions.WriteFunction(m_specification, m_cgd, CF, m_specification.m_inlineFunctions, staticFunc, exFuncName, FAI, I, comment);
        }