/// <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; }
public static G25.VariableType CreateSyntheticSMVtype(Specification S, CGdata cgd, FloatType FT, RefGA.Multivector value) { // make up list of basis blades rsbbp.BasisBlade[] L = new rsbbp.BasisBlade[value.BasisBlades.Length]; for (int i = 0 ; i < value.BasisBlades.Length; i++) { RefGA.BasisBlade B = value.BasisBlades[i]; if (B.symScale == null) L[i] = new rsbbp.BasisBlade(new RefGA.BasisBlade(B.bitmap), B.scale); // constant value else L[i] = new rsbbp.BasisBlade(new RefGA.BasisBlade(B.bitmap)); // non-const value } // get other required info String name = "nameOfType"; SMV.MULTIVECTOR_TYPE mvType = SMV.MULTIVECTOR_TYPE.MULTIVECTOR; String comment = "MISSING; PLEASE ADD TO SPECIFICATION"; //String constantName = null; // create the type G25.SMV synSMV = new G25.SMV(name, L, mvType, comment); // throw exception throw new G25.UserException("Missing specialized multivector type.\n" + "Please add the following XML to the specification to fix the dependency:\n" + XML.SMVtoXmlString(S, synSMV)); }
/// <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 + ")"; }
protected void SanityCheckAllBladesPresent(RefGA.BasisBlade[][] L, int spaceDim, String[] bvNames, String domainOrRangeStr) { bool[] present = new bool[1 << spaceDim]; for (int i = 0; i < L.Length; i++) { for (int j = 0; j < L[i].Length; j++) { present[L[i][j].bitmap] = true; } } for (int i = 0; i < present.Length; i++) if (!present[i]) throw new G25.UserException("In outermorphism type " + Name + ":\n" + "Missing basis blade '" + new RefGA.BasisBlade((uint)i).ToString(bvNames) + "' in " + domainOrRangeStr); }
/// <summary> /// Converts a symbolic multivector value to a textual description of the specialized multivector /// type that would be required to store that value. This is used for presenting error messages /// to users when a suitable specialized type cannot be found for a specific multivector value. /// </summary> /// <param name="S">Specification, used for basis vector names.</param> /// <param name="value">The value to describe.</param> /// <returns>Textual description of the type that can store 'value'.</returns> public static String MultivectorToTypeDescription(G25.Specification S, RefGA.Multivector value) { StringBuilder SB = new StringBuilder(); bool appendSpace = false; foreach (RefGA.BasisBlade B in value.BasisBlades) { if (appendSpace) SB.Append(" "); SB.Append(new RefGA.BasisBlade(B.bitmap).ToString(S.m_basisVectorNames)); if (B.symScale == null) SB.Append("=" + B.scale); appendSpace = true; } return SB.ToString(); }
/// <summary> /// Returns the element index of basis blade 'B' or -1 when not represented by this MV. /// /// Example: suppose you want to know the group and element index of B=e2^e3^no, /// then (assuming it is represented), it is in BasisBlade(groupIdx, elemIdx). /// </summary> /// <param name="B">The basis blade whose bitmap is looked up.</param> /// <returns>-1 if 'B' is cannot be represented by this MV, otherwise, the index of the element in the group.</returns> public int GetElementIdx(RefGA.BasisBlade B) { if ((B.bitmap >= m_bitmapToGroup.Length) || (m_bitmapToGroup[B.bitmap] < 0)) return -1; else return m_bitmapToGroup[B.bitmap] & 0xFFFF; }
/// <returns>true if m_basisBlades matches 'L' (used to see if basis blades are in the default order and orientation).</returns> public bool CompareBasisBladeOrder(RefGA.BasisBlade[][] L) { if (L.Length != m_basisBlades.Length) return false; for (int i = 0; i < L.Length; i++) { if (L[i].Length != m_basisBlades[i].Length) return false; for (int j = 0; j < L[i].Length; j++) if ((L[i][j].CompareTo(m_basisBlades[i][j])) != 0) return false; } return true; }
private static void WriteGetCoordFunction(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, string gmvTypeName, int groupIdx, int elementIdx, RefGA.BasisBlade B) { string bladeName = B.ToLangString(S.m_basisVectorNames); string funcName = G25.CG.Shared.Main.GETTER_PREFIX + bladeName; string funcDecl = "\t" + Keywords.PublicAccessModifier(S) + " " + FT.type + " " + funcName + "() "; int nbTabs = 1; new G25.CG.Shared.Comment("Returns the " + bladeName + " coordinate of this " + gmvTypeName).Write(SB, S, nbTabs); SB.Append(funcDecl); SB.AppendLine(" {"); SB.AppendLine("\t\treturn (m_c[" + groupIdx + "] == null) ? " + FT.DoubleToString(S, 0.0) + ": " + "m_c[" + groupIdx + "][" + elementIdx + "];"); SB.AppendLine("\t}"); }
private static void WriteCoordExtractFunction(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, string gmvTypeName, int groupIdx, int elementIdx, RefGA.BasisBlade B) { StringBuilder declSB = cgd.m_declSB; StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; String bladeName = B.ToLangString(S.m_basisVectorNames); string varName = "A"; // do we inline this func? string inlineStr = G25.CG.Shared.Util.GetInlineString(S, S.m_inlineSet, " "); string funcName = gmvTypeName + "_" + bladeName; string funcDecl = inlineStr + FT.type + " " + funcName + "(const " + gmvTypeName + " *" + varName + ")"; string comment = "/** Returns the " + B.ToString(S.m_basisVectorNames) + " coordinate of '" + varName + "' */"; // declSB.AppendLine("/* group : " + groupIdx + " element: " + elementIdx + "*/"); declSB.AppendLine(comment); declSB.Append(funcDecl); declSB.AppendLine(";"); defSB.AppendLine(""); defSB.Append(funcDecl); defSB.AppendLine(" {"); defSB.AppendLine("\treturn (" + varName + "->gu & " + (1 << groupIdx) + ") ? " + varName + "->c[" + S.m_namespace + "_mvSize[" + varName + "->gu & " + ((1 << groupIdx) - 1) + "] + " + elementIdx + "] : " + FT.DoubleToString(S, 0.0) + ";"); defSB.AppendLine("}"); // add extract coord extract function for scalar if (B.Grade() == 0) { string floatFuncName = gmvTypeName + "_" + FT.type; string floatFuncDecl = inlineStr + FT.type + " " + floatFuncName + "(const " + gmvTypeName + " *" + varName + ")"; declSB.AppendLine(comment); declSB.Append(floatFuncDecl); declSB.AppendLine(";"); defSB.Append(floatFuncDecl); defSB.AppendLine(" {"); defSB.AppendLine("\treturn " + funcName + "(" + varName + ");"); defSB.AppendLine("}"); } }
/// <summary> /// Little helper function for the constructor. /// </summary> /// <returns>'basisBlades', but inside a newly allocated array of length 1.</returns> protected static RefGA.BasisBlade[][] ToDoubleArray(RefGA.BasisBlade[] basisBlades) { RefGA.BasisBlade[][] B = new RefGA.BasisBlade[1][]; B[0] = basisBlades; return B; }
private static void WriteSetCoordFunction(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, StringBuilder SB, string gmvTypeName, int groupIdx, int elementIdx, int groupSize, RefGA.BasisBlade B) { string bladeName = B.ToLangString(S.m_basisVectorNames); // do we inline this func? string inlineStr = "inline "; string funcName = MainGenerator.SETTER_PREFIX + bladeName; string coordName = "val"; string funcDecl = "\t" + inlineStr + "void " + funcName + "(" + FT.type + " " + coordName + ") "; SB.AppendLine("\t/// Sets the " + bladeName + " coordinate of this " + gmvTypeName + "."); SB.Append(funcDecl); SB.AppendLine(" {"); SB.AppendLine("\t\treserveGroup_" + groupIdx + "();"); SB.AppendLine("\t\tm_c[" + S.m_namespace + "_mvSize[m_gu & " + ((1 << groupIdx) - 1) + "] + " + elementIdx + "] = " + coordName + ";"); SB.AppendLine("\t}"); }
/// <summary> /// Returns the group index of basis blade 'B' or -1 when not represented by this MV. /// /// Example: suppose you want to know the group and element index of B=e2^e3^no, /// then (assuming it is represented), it is in m_basisBlades[GetGroupIdx(B)][GetElementIdx(B)]. /// </summary> /// <param name="B">The basis blade whose bitmap is looked up.</param> /// <returns>-1 if 'B' is cannot be represented by this MV, otherwise, the index of the group.</returns> public int GetGroupIdx(RefGA.BasisBlade B) { if ((B.bitmap >= m_bitmapToGroup.Length) || (m_bitmapToGroup[B.bitmap] < 0)) return -1; else return m_bitmapToGroup[B.bitmap] >> 16; }
// false means 'not specialized' /// <summary> /// Constructor. /// </summary> /// <param name="name">The name of the multivector, for example "mv" or "rotor".</param> /// <param name="basisBlades">The basis blades, by group. Each entry in the array is a group of coordinates.</param> /// <param name="m">Memory allocation method.</param> public GMV(String name, RefGA.BasisBlade[][] basisBlades, MEM_ALLOC_METHOD m) : base(false, name, basisBlades) { m_memoryAllocationMethod = m; }
/// <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 + ")"; } }
/// <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; } }
/// <summary> /// Generates code to assign <c>value</c> to a variable whose coordinate order is specified by <c>BL</c>. /// /// For example, <c>BL</c> could be <c>[e1, e2, e3]</c> and the multivector value <c>[e1 - 2e3]</c>. /// Then the returned array would be <c>["1", "0", "-2"]</c>. /// /// Parts of <c>value</c> that cannot be assigned to <c>BL</c> are silently ignored. /// /// Possibly, at some point we would like to generate some kind of warning? /// </summary> /// <param name="S">Specification of algebra (not used yet).</param> /// <param name="FT">Floating point type of assigned variable (used for casting strings).</param> /// <param name="mustCast">Set to true if a cast to 'FT' must be performed.</param> /// <param name="BL">Basis blades of assigned variable.</param> /// <param name="value">Multivector value to assign to the list of basis blades. /// Must not contain basis blades inside the symbolic scalars of the RefGA.BasisBlades.</param> /// <param name="writeZeros">When true, <c>"0"</c> will be returned when no value should be assigned /// to some coordinate. <c>null</c> otherwise.</param> /// <returns>An array of strings which tell you what to assign to each coordinate.</returns> public static String[] GetAssignmentStrings(Specification S, FloatType FT, bool mustCast, RefGA.BasisBlade[] BL, RefGA.Multivector value, bool writeZeros) { String[] assignedStr = new String[BL.Length]; int idx = 0; // for each non-const coord, find out what value is (loop through all entries in value) foreach (RefGA.BasisBlade B in BL) { // find same basisblade in 'value' foreach (RefGA.BasisBlade C in value.BasisBlades) { if (C.bitmap == B.bitmap) // match found: get assignment string { // compute D = inverse(B) . C; RefGA.BasisBlade Bi = (new RefGA.BasisBlade(B.bitmap, 1.0 / B.scale)).Reverse(); RefGA.BasisBlade D = RefGA.BasisBlade.scp(Bi, C); if (mustCast) assignedStr[idx] = FT.castStr + "(" + CodeUtil.ScalarToLangString(S, FT, D) + ")"; else assignedStr[idx] = CodeUtil.ScalarToLangString(S, FT, D); break; } } if (writeZeros && (assignedStr[idx] == null)) // has an assignment string been set? { // no assignment: simply assign "0" assignedStr[idx] = FT.DoubleToString(S, 0.0); } idx++; } return assignedStr; }
/// <summary> /// Generates the code to assign a multivector value (which may have symbolic coordinates) to a specialized multivector. /// </summary> /// <param name="S">Specification of algebra. Used to known names of basis vector, output language, access strings, etc.</param> /// <param name="FT">Floating point type of destination.</param> /// <param name="mustCast">Set to true if a cast to 'FT' must be performed before assigned to 'dstName'.</param> /// <param name="dstSmv">Type of specialized multivector assigned to.</param> /// <param name="dstName">Name of specialized multivector assigned to.</param> /// <param name="dstPtr">Is the destination of pointer?</param> /// <param name="value">Multivector value to assign to the SMV. Must not contain basis blades inside the symbolic scalars.</param> /// <param name="nbTabs">Number of tabs to put before the code.</param> /// <param name="writeZeros">Some callers want to skip <c>"= 0.0"</c> assignments because they would be redundant. For /// example the caller may know that the destination is already set to zero. If so, set this argument to false and /// code for setting coordinates to 0 will not be generated.</param> /// <returns>String of code for dstName = value;</returns> public static string GenerateSMVassignmentCode(Specification S, FloatType FT, bool mustCast, G25.SMV dstSmv, String dstName, bool dstPtr, RefGA.Multivector value, int nbTabs, bool writeZeros) { RefGA.BasisBlade[] BL = BasisBlade.GetNonConstBladeList(dstSmv); string[] accessStr = GetAccessStr(S, dstSmv, dstName, dstPtr); string[] assignedStr = GetAssignmentStrings(S, FT, mustCast, BL, value, writeZeros); //int nbTabs = 1; return GenerateAssignmentCode(S, accessStr, assignedStr, nbTabs, writeZeros); }
/// <summary> /// Generates code for returning a scalar value. The input is a scalar-valued multivector. /// </summary> /// <param name="S">Specification (used for output language).</param> /// <param name="FT">Floating point type which must be returned.</param> /// <param name="mustCast">Set to true if the returned value must be cast to <c>FT</c>, that is /// if you are not sure that the multivector has the same float type as the return type <c>FT</c>.</param> /// <param name="value">The symbolic multivector value to be returned.</param> /// <returns>Code for returning a scalar value.</returns> public static string GenerateScalarReturnCode(Specification S, FloatType FT, bool mustCast, RefGA.Multivector value) { if (value.IsZero()) { return "return " + FT.DoubleToString(S, 0.0) + ";"; } else { return "return " + ((mustCast) ? (FT.castStr + "(") : "") + CodeUtil.ScalarToLangString(S, FT, value.BasisBlades[0]) + ((mustCast) ? ")" : "") + ";"; } }
/// <summary> /// Computes which groups would be used to store the basis blades used in 'B'. /// </summary> /// <param name="B">A list of basis blades.</param> /// <returns>A bitmap representing the groups that would be used to store 'B'.</returns> public int GetGroupUsageBitmap(RefGA.BasisBlade[] B) { int gu = 0; foreach (BasisBlade b in B) { gu |= 1 << GetGroupIdx(b); } return gu; }
/// <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]); }
// true means 'specialized' /// <summary> /// Constructor. /// </summary> /// <param name="name">The name of the multivector, for example "mv" or "rotor".</param> /// <param name="basisBlades">The basis blades.</param> /// <param name="isConstant">Some coordinates may have constant values. If a coordinate is constant, its respective entry in isConstant is true (May be null).</param> /// <param name="constantValues">Some coordinates may have constant values. This array lists the values for each basis blade (May be null).</param> /// <param name="mvType">Type of multivector (</param> /// <param name="comment">A comment on the multivector type that may appear in the generated documentation. May be null.</param> public SMV(string name, RefGA.BasisBlade[] basisBlades, MULTIVECTOR_TYPE mvType, bool[] isConstant, double[] constantValues, string comment) : base(true, name, ToDoubleArray(basisBlades)) { // sanity check if (comment == null) comment = ""; if (((isConstant != null) && (basisBlades.Length != isConstant.Length)) || ((constantValues != null) && (basisBlades.Length != constantValues.Length))) throw new Exception("G25.SMV(): the 'isConstant' array or the 'constantValues' array do not match the length of the 'basisBlades' array"); m_mvType = mvType; m_isConstant = (isConstant == null) ? new bool[basisBlades.Length]: (bool[])isConstant.Clone(); m_constantValues = (constantValues == null) ? new double[basisBlades.Length] : (double[])constantValues.Clone(); m_comment = comment; // count number of constant coordinates int nbConstant = GetNbConstantCoordinates(); // sanity check number of constant coordinates /*if ((m_constantName != null) && (nbConstant != basisBlades.Length) && (nbConstant != m_constantValues.Length)) throw new Exception("G25.SMV(): not all coordinates of the constant '" + m_constantName + "' are constant");*/ InitConstBasisBladeIdx(nbConstant); }
/// <summary> /// Constructor for a BasisBlade without a constant coordinate value /// </summary> public BasisBlade(RefGA.BasisBlade B) { m_basisBlade = B; m_isConstant = false; m_constantValue = 0.0; }
private static void WriteGetCoordFunction(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, StringBuilder SB, string gmvTypeName, int groupIdx, int elementIdx, RefGA.BasisBlade B) { string bladeName = B.ToLangString(S.m_basisVectorNames); // do we inline this func? string inlineStr = "inline "; string funcName = MainGenerator.GETTER_PREFIX + bladeName; string funcDecl = "\t" + inlineStr + FT.type + " " + funcName + "() const"; SB.AppendLine("\t/// Returns the " + bladeName + " coordinate of this " + gmvTypeName + "."); SB.Append(funcDecl); SB.AppendLine(" {"); SB.AppendLine("\t\treturn (m_gu & " + (1 << groupIdx) + ") ? " + "m_c[" + S.m_namespace + "_mvSize[m_gu & " + ((1 << groupIdx) - 1) + "] + " + elementIdx + "] : " + FT.DoubleToString(S, 0.0) + ";"); SB.AppendLine("\t}"); }
/// <summary> /// Constructor for a BasisBlade with a constant coordinate value /// </summary> /// <param name="B"></param> /// <param name="constantValue"></param> public BasisBlade(RefGA.BasisBlade B, double constantValue) { m_basisBlade = B; m_isConstant = true; m_constantValue = constantValue; }
/// <summary> /// Substitutes all symbolic scalars for doubles (as evaluated by <paramref name="E"/>) /// and evaluates the symbolic ScalarOps. E.g. sqrt(2.0) would evaluate to 1.4142... /// </summary> /// <param name="E">SymbolicEvaluator used to evaluate the symbolic scalars</param> /// <returns></returns> public double SymbolicEval(RefGA.Symbolic.SymbolicEvaluator E) { Multivector A = m_value1.SymbolicEval(E); Multivector B = m_value2.SymbolicEval(E); if (!(A.IsScalar() && B.IsScalar())) throw new ArgumentException("BinaryScalarOp.SymbolicEval: argument is not scalar"); double a = A.RealScalarPart(); double b = B.RealScalarPart(); if (m_opName == ATAN2) { return Math.Atan2(a, b); } else throw new ArgumentException("BinaryScalarOp.SymbolicEval: unknown opname " + m_opName); }
/// <summary> /// Substitutes all symbolic scalars for doubles (as evaluated by <paramref name="E"/>) /// and evaluates the symbolic ScalarOps. E.g. sqrt(2.0) would evaluate to 1.4142... /// </summary> /// <param name="E">SymbolicEvaluator used to evaluate the symbolic scalars</param> /// <returns></returns> public double SymbolicEval(RefGA.Symbolic.SymbolicEvaluator E) { Multivector V = m_value.SymbolicEval(E); if (!V.IsScalar()) throw new ArgumentException("UnaryScalarOp.SymbolicEval: argument is not scalar"); double v = V.RealScalarPart(); if (m_opName == INVERSE) { if (v == 0.0) throw new ArgumentException("UnaryScalarOp.SymbolicEval: divide by zero"); return 1.0 / v; } else if (m_opName == SQRT) { if (v < 0.0) throw new ArgumentException("UnaryScalarOp.SymbolicEval: square root of negative value"); else return Math.Sqrt(v); } else if (m_opName == EXP) { return Math.Exp(v); } else if (m_opName == LOG) { if (v <= 0.0) throw new ArgumentException("UnaryScalarOp.SymbolicEval: logarithm of value <= 0"); else return Math.Log(v); } else if (m_opName == SIN) { return Math.Sin(v); } else if (m_opName == COS) { return Math.Cos(v); } else if (m_opName == TAN) { // how to detect bad input (1/2 pi, etc)? return Math.Tan(v); } else if (m_opName == SINH) { return Math.Sinh(v); } else if (m_opName == COSH) { return Math.Cosh(v); } else if (m_opName == TANH) { return Math.Tanh(v); } else if (m_opName == ABS) { return Math.Abs(v); } else throw new ArgumentException("UnaryScalarOp.SymbolicEval: unknown opname " + m_opName); }
private static void WriteSetCoordFunction(StringBuilder SB, Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, string gmvTypeName, int groupIdx, int elementIdx, int groupSize, RefGA.BasisBlade B) { string bladeName = B.ToLangString(S.m_basisVectorNames); string funcName = G25.CG.Shared.Main.SETTER_PREFIX + bladeName; string coordName = "val"; string funcDecl = "\t" + Keywords.PublicAccessModifier(S) + " void " + funcName + "(" + FT.type + " " + coordName + ") "; SB.AppendLine("\t/// Sets the " + bladeName + " coordinate of this " + gmvTypeName + "."); SB.Append(funcDecl); SB.AppendLine(" {"); SB.AppendLine("\t\t" + GetReserveGroupString(S, groupIdx) + "();"); SB.AppendLine("\t\tm_c[" + groupIdx + "][" + elementIdx + "] = " + coordName + ";"); SB.AppendLine("\t}"); }
/// <summary> /// Constructor. /// </summary> /// <param name="name">The name of the multivector (typically smvom_gradeX_columnY.</param> /// <param name="basisBlades">The basis blades.</param> /// <param name="parentOM">Parent outermorphism this SMVOM belongs to.</param> /// <param name="gradeOM">The grade this SMVOM is for.</param> /// <param name="columnOM">The column of the OM matrix this SMVOM is for.</param> public SMVOM(String name, RefGA.BasisBlade[] basisBlades, G25.OM parentOM, int gradeOM, int columnOM) : base(name, basisBlades, MULTIVECTOR_TYPE.MULTIVECTOR, null, null, null) { m_parentOM = parentOM; m_gradeOM = gradeOM; m_columnOM = columnOM; }
private static void WriteCoordSetFunction(Specification S, G25.CG.Shared.CGdata cgd, G25.FloatType FT, string gmvTypeName, int groupIdx, int elementIdx, int groupSize, RefGA.BasisBlade B) { StringBuilder declSB = cgd.m_declSB; StringBuilder defSB = (S.m_inlineSet) ? cgd.m_inlineDefSB : cgd.m_defSB; String bladeName = B.ToLangString(S.m_basisVectorNames); string varName = "A"; string coordName = bladeName + "_coord"; // do we inline this func? string inlineStr = G25.CG.Shared.Util.GetInlineString(S, S.m_inlineSet, " "); string funcName = gmvTypeName + "_set_" + bladeName; string funcDecl = inlineStr + "void " + funcName + "(" + gmvTypeName + " *" + varName + ", " + FT.type + " " + coordName + ")"; declSB.AppendLine("/** Sets the " + B.ToString(S.m_basisVectorNames) + " coordinate of '" + varName + "' */"); declSB.Append(funcDecl); declSB.AppendLine(";"); defSB.AppendLine(""); defSB.Append(funcDecl); defSB.AppendLine(" {"); defSB.AppendLine("\t" + gmvTypeName + "_reserveGroup_" + groupIdx + "(" + varName + ");"); defSB.AppendLine("\t" + varName + "->c[" + S.m_namespace + "_mvSize[" + varName + "->gu & " + ((1 << groupIdx) - 1) + "] + " + elementIdx + "] = " + coordName + ";"); defSB.AppendLine("}"); }
/// <summary> /// Constructor. Do not use directly. Use the constructors of G25.GMV and /// G25.SMV instead. /// /// If the multivector is specialized, basisBlades.Length must be 1. /// </summary> /// <param name="specialized">Whether this is a specialized MV or not.</param> /// <param name="name">The name of the multivector, for example "mv" or "rotor".</param> /// <param name="basisBlades">The basis blades, by group. Each entry in the array is a group of coordinates. /// Specialized multivector have only one group.</param> protected MV(bool specialized, String name, RefGA.BasisBlade[][] basisBlades) { if (specialized && (basisBlades.Length != 1)) throw new Exception("G25.MV(): specialized multivector classes must have one group"); m_specialized = specialized; m_name = name; m_basisBlades = new RefGA.BasisBlade[basisBlades.Length][]; for (int i = 0; i < basisBlades.Length; i++) { m_basisBlades[i] = (RefGA.BasisBlade[])basisBlades[i].Clone(); } { // init m_bitmapToGroup // get maximum dimension used in any of the basis blades: int maxDim = 0; for (int i = 0; i < m_basisBlades.Length; i++) { for (int j = 0; j < m_basisBlades[i].Length; j++) { int d = RefGA.Bits.HighestOneBit(m_basisBlades[i][j].bitmap); if (d > maxDim) maxDim = d; } } // allocate m_bitmapToGroup, set all to -1 m_bitmapToGroup = new int[1 << (maxDim+1)]; for (int i = 0; i < m_bitmapToGroup.Length; i++) m_bitmapToGroup[i] = -1; // mark used position with group and element index for (int i = 0; i < m_basisBlades.Length; i++) for (int j = 0; j < m_basisBlades[i].Length; j++) m_bitmapToGroup[m_basisBlades[i][j].bitmap] = (i << 16) | j; } }