Exemple #1
0
        public void ParseUnitTest()
        {
            UnitsCore uc  = new UnitsCore();
            var       cm  = new Unit("cm", Dimensions.Length, 0.01);
            var       ft  = new Unit("ft", Dimensions.Length, 0.3048);
            var       min = new Unit("min", Dimensions.Time, 60.0);
            var       s   = new Unit("s", Dimensions.Time, 1.0);
            var       cfm = new Unit("CFM", ft.Pow(3) / min);

            uc.RegisterUnit(cm);
            uc.RegisterUnit(s);
            var u1 = uc.ParseUnit("cm");

            Assert.IsTrue(u1 == cm);
            var u2 = uc.ParseUnit("cm*cm");

            Assert.IsTrue(u2 == cm * cm);
            var u3 = uc.ParseUnit("cm^2");

            Assert.IsTrue(u3 == cm * cm);
            var u4 = uc.ParseUnit("cm^2.5/cm^1.5");

            Assert.IsTrue(u4 == cm);
            //flow over area -> speed
            var u5 = uc.ParseUnit("cm^3*s^-1/cm^2");

            Assert.IsTrue(u5 == cm / s);
        }
        public void BuildTest()
        {
            UnitsCore uc = new UnitsCore();

            uc.RegisterUnit(new Unit("Pa", Dimensions.Pressure, 1));
            var tokenizer = new TokenReader();
            var tokens    = tokenizer.Read("-1+2-3[Pa]^2*33.21+1e-8");
            var ast       = new AstBuilder(null).Build(tokens, uc);
        }
Exemple #3
0
        public void ParseNumberTest()
        {
            UnitsCore uc  = new UnitsCore();
            var       kPa = new Unit("kPa", Dimensions.Pressure, 1000);

            uc.RegisterUnit(kPa);
            var un = uc.ParseNumber("101.325[kPa]");

            Assert.AreEqual(un.Number, 101.325, 1e-8);
            Assert.IsTrue(un.Unit == kPa);
        }
Exemple #4
0
        /// <summary>
        /// Creates a new instance of the <see cref="CalculationEngine"/> class.
        /// </summary>
        /// <param name="cultureInfo">
        /// The <see cref="CultureInfo"/> required for correctly reading floating poin numbers.
        /// </param>
        /// <param name="executionMode">The execution mode that must be used for formula execution.</param>
        /// <param name="cacheEnabled">Enable or disable caching of mathematical formulas.</param>
        /// <param name="optimizerEnabled">Enable or disable optimizing of formulas.</param>
        /// <param name="defaultFunctions">Enable or disable the default functions.</param>
        /// <param name="defaultConstants">Enable or disable the default constants.</param>
        public CalculationEngine(UnitsCore unitsCore, CultureInfo cultureInfo, ExecutionMode executionMode, bool cacheEnabled,
                                 bool optimizerEnabled, bool defaultFunctions, bool defaultConstants)
        {
            this.executionFormulaCache = new MemoryCache <string, Func <IDictionary <string, ExecutionResult>, ExecutionResult> >();
            this.FunctionRegistry      = new FunctionRegistry(false);
            this.ConstantRegistry      = new ConstantRegistry(false);
            this.cultureInfo           = cultureInfo;
            this.cacheEnabled          = cacheEnabled;
            this.optimizerEnabled      = optimizerEnabled;
            this.unitsCore             = unitsCore;
            if (executionMode == ExecutionMode.Interpreted)
            {
                executor = new Interpreter();
            }
            else if (executionMode == ExecutionMode.Compiled)
            {
                executor = new DynamicCompiler();
            }
            else
            {
                throw new ArgumentException(string.Format("Unsupported execution mode \"{0}\".", executionMode),
                                            "executionMode");
            }

            optimizer = new Optimizer(new Interpreter()); // We run the optimizer with the interpreter

            // Register the default constants of Jace.NET into the constant registry
            if (defaultConstants)
            {
                RegisterDefaultConstants();
            }

            // Register the default functions of Jace.NET into the function registry
            if (defaultFunctions)
            {
                RegisterDefaultFunctions();
            }
        }
Exemple #5
0
 /// <summary>
 /// Creates a new instance of the <see cref="CalculationEngine"/> class.
 /// </summary>
 /// <param name="cultureInfo">
 /// The <see cref="CultureInfo"/> required for correctly reading floating poin numbers.
 /// </param>
 /// <param name="executionMode">The execution mode that must be used for formula execution.</param>
 /// <param name="cacheEnabled">Enable or disable caching of mathematical formulas.</param>
 /// <param name="optimizerEnabled">Enable or disable optimizing of formulas.</param>
 public CalculationEngine(UnitsCore unitsCore, CultureInfo cultureInfo, ExecutionMode executionMode, bool cacheEnabled, bool optimizerEnabled)
     : this(unitsCore, cultureInfo, executionMode, cacheEnabled, optimizerEnabled, true, true)
 {
 }
Exemple #6
0
 /// <summary>
 /// Creates a new instance of the <see cref="CalculationEngine"/> class. The optimizer and
 /// cache are enabled.
 /// </summary>
 /// <param name="cultureInfo">
 /// The <see cref="CultureInfo"/> required for correctly reading floating poin numbers.
 /// </param>
 /// <param name="executionMode">The execution mode that must be used for formula execution.</param>
 public CalculationEngine(UnitsCore unitsCore, CultureInfo cultureInfo, ExecutionMode executionMode)
     : this(unitsCore, cultureInfo, executionMode, true, true)
 {
 }
Exemple #7
0
 /// <summary>
 /// Creates a new instance of the <see cref="CalculationEngine"/> class. The dynamic compiler
 /// is used for formula execution and the optimizer and cache are enabled.
 /// </summary>
 /// <param name="cultureInfo">
 /// The <see cref="CultureInfo"/> required for correctly reading floating poin numbers.
 /// </param>
 public CalculationEngine(UnitsCore unitsCore, CultureInfo cultureInfo)
     : this(unitsCore, cultureInfo, ExecutionMode.Compiled)
 {
 }
Exemple #8
0
 /// <summary>
 /// Creates a new instance of the <see cref="CalculationEngine"/> class with
 /// default parameters.
 /// </summary>
 public CalculationEngine(UnitsCore unitsCore)
     : this(unitsCore, CultureInfo.CurrentCulture, ExecutionMode.Compiled)
 {
 }
Exemple #9
0
        public void CalculateTest()
        {
            UnitsCore uc   = new UnitsCore();
            var       inch = new Unit("in", Dimensions.Length, 0.0254);
            var       foot = new Unit("ft", 12 * inch);
            var       sec  = new Unit("s", Dimensions.Time, 1.0);
            var       min  = new Unit("min", Dimensions.Time, 60);
            var       cfm  = new Unit("CFM", foot.Pow(3) / min);

            uc.RegisterUnit(cfm);
            uc.RegisterUnit(inch);
            uc.RegisterUnit(foot);
            uc.RegisterUnit(sec);
            var oneFoot = new UnitNumber(1, foot);
            var ce      = new CalculationEngine(uc);
            var vars    = new Dictionary <string, ExecutionResult>();

            vars.Add("A", new ExecutionResult(1));
            vars.Add("B", new ExecutionResult(oneFoot));
            ExecutionResult result;

            //A number
            result = ce.Calculate("1.515");
            Assert.AreEqual(result.DataType, DataType.Number);
            Assert.AreEqual((double)result.Value, 1.515, 1e-8);
            //A number with unit
            result = ce.Calculate("1.0[ft]");
            Assert.AreEqual(result.DataType, DataType.UnitNumber);
            Assert.IsTrue((UnitNumber)result.Value == oneFoot);
            result = ce.Calculate("-1.0[ft]");
            Assert.AreEqual(result.DataType, DataType.UnitNumber);
            Assert.IsTrue((UnitNumber)result.Value == -oneFoot);
            //Unitless calculations
            result = ce.Calculate("1+0.515");
            Assert.AreEqual(result.DataType, DataType.Number);
            Assert.AreEqual((double)result.Value, 1.515, 1e-8);
            //Calculations with unit
            result = ce.Calculate("0.5[ft]+6[in]");
            Assert.AreEqual(result.DataType, DataType.UnitNumber);
            Assert.IsTrue((UnitNumber)result.Value == oneFoot);
            //Constant
            result = ce.Calculate("pi");
            Assert.AreEqual(result.DataType, DataType.Number);
            Assert.AreEqual((double)result.Value, Math.PI, 1e-8);
            result = ce.Calculate("-pi");
            Assert.AreEqual(result.DataType, DataType.Number);
            Assert.AreEqual((double)result.Value, -Math.PI, 1e-8);
            result = ce.Calculate("1-pi");
            Assert.AreEqual(result.DataType, DataType.Number);
            Assert.AreEqual((double)result.Value, 1 - Math.PI, 1e-8);
            //Variable
            result = ce.Calculate("B", vars);
            Assert.AreEqual(result.DataType, DataType.UnitNumber);
            Assert.IsTrue((UnitNumber)result.Value == oneFoot);
            result = ce.Calculate("-B", vars);
            Assert.AreEqual(result.DataType, DataType.UnitNumber);
            Assert.IsTrue((UnitNumber)result.Value == -oneFoot);
            result = ce.Calculate("1[ft]-B", vars);
            Assert.AreEqual(result.DataType, DataType.UnitNumber);
            Assert.IsTrue((UnitNumber)result.Value == oneFoot - oneFoot);
            //Function with number
            result = ce.Calculate("sin(3.1415926535897932384626433832795)", vars);
            Assert.AreEqual(result.DataType, DataType.Number);
            Assert.AreEqual((double)result.Value, Math.Sin(Math.PI), 1e-8);
            result = ce.Calculate("sin(3.1415926535897932384626433832795/3)", vars);
            Assert.AreEqual(result.DataType, DataType.Number);
            Assert.AreEqual((double)result.Value, Math.Sin(Math.PI / 3), 1e-8);
            //Function with constant
            result = ce.Calculate("sin(pi)", vars);
            Assert.AreEqual(result.DataType, DataType.Number);
            Assert.AreEqual((double)result.Value, Math.Sin(Math.PI), 1e-8);
            result = ce.Calculate("sin(pi/3)", vars);
            Assert.AreEqual(result.DataType, DataType.Number);
            Assert.AreEqual((double)result.Value, Math.Sin(Math.PI / 3), 1e-8);
            //Function with variable
            result = ce.Calculate("sin(A)", vars);
            Assert.AreEqual(result.DataType, DataType.Number);
            Assert.AreEqual((double)result.Value, Math.Sin(1.0), 1e-8);
        }
Exemple #10
0
        public Operation Build(IList <Token> tokens, UnitsCore unitsCore)
        {
            resultStack.Clear();
            operatorStack.Clear();

            parameterCount.Clear();

            foreach (Token token in tokens)
            {
                object value = token.Value;

                switch (token.TokenType)
                {
                case TokenType.Number:
                    resultStack.Push(new FloatingPointConstant((double)token.Value));
                    break;

                case TokenType.Text:
                    if (functionRegistry.IsFunctionName((string)token.Value))
                    {
                        operatorStack.Push(token);
                        parameterCount.Push(1);
                    }
                    else
                    {
                        resultStack.Push(new Variable(((string)token.Value).ToLowerInvariant()));
                    }
                    break;

                case TokenType.Unit:
                    resultStack.Push(new ChangeUnit(resultStack.Pop(), unitsCore.ParseUnit((string)token.Value)));
                    //perform unit conversion
                    break;

                case TokenType.LeftBracket:
                    operatorStack.Push(token);
                    break;

                case TokenType.RightBracket:
                    PopOperations(true, token);
                    //parameterCount.Pop();
                    break;

                case TokenType.ArgumentSeparator:
                    PopOperations(false, token);
                    parameterCount.Push(parameterCount.Pop() + 1);
                    break;

                case TokenType.Operation:
                    Token operation1Token = token;
                    char  operation1      = (char)operation1Token.Value;

                    while (operatorStack.Count > 0 && (operatorStack.Peek().TokenType == TokenType.Operation ||
                                                       operatorStack.Peek().TokenType == TokenType.Text))
                    {
                        Token operation2Token        = operatorStack.Peek();
                        bool  isFunctionOnTopOfStack = operation2Token.TokenType == TokenType.Text;

                        if (!isFunctionOnTopOfStack)
                        {
                            char operation2 = (char)operation2Token.Value;

                            if ((IsLeftAssociativeOperation(operation1) &&
                                 operationPrecedence[operation1] <= operationPrecedence[operation2]) ||
                                (operationPrecedence[operation1] < operationPrecedence[operation2]))
                            {
                                operatorStack.Pop();
                                resultStack.Push(ConvertOperation(operation2Token));
                            }
                            else
                            {
                                break;
                            }
                        }
                        else
                        {
                            operatorStack.Pop();
                            resultStack.Push(ConvertFunction(operation2Token));
                        }
                    }

                    operatorStack.Push(operation1Token);
                    break;
                }
            }

            PopOperations(false, null);

            VerifyResultStack();

            return(resultStack.First());
        }