private static Entity EvalMultiplicationOperator(Entity oa, Entity ob)
        {
            NumberEntity   na = null, nb = null;
            VariableEntity va = null, vb = null;

            if ((oa.IsVariableEntity(out va) || ob.IsVariableEntity(out vb)) &&
                (oa.IsNumberEntity(out na) || ob.IsNumberEntity(out nb)))
            {
                return(EvalMultiplicationOperator(va == null ? vb : va, na == null ? nb : na));
            }

            var    oaChildren = GetSumOrSubEntities(oa);
            var    obChildren = GetSumOrSubEntities(ob);
            Entity result     = null;

            foreach (var oaChild in oaChildren)
            {
                foreach (var obChild in obChildren)
                {
                    if (result == null)
                    {
                        result = oaChild * obChild;
                    }
                    else
                    {
                        result = result + (oaChild * obChild);
                    }
                }
            }

            return(result.Eval());
        }
        public void Assign(VariableEntity variable, NumberEntity number)
        {
            var children = new List <VariableEntity>();

            GetVariables(variable, children);
            foreach (var child in children)
            {
                child.AssignNumber(number);
            }
        }
        private Entity EvalNumber(NumberEntity na, NumberEntity nb)
        {
            switch (Name)
            {
            case Constants.Operators.MUL:
                return(na.Number * nb.Number);

            case Constants.Operators.SUM:
                return(na.Number + nb.Number);

            case Constants.Operators.DIV:
                return(na.Number / nb.Number);

            default:
                return(na.Number - nb.Number);
            }
        }
        public override Entity Eval()
        {
            VariableEntity va = null, vb = null;
            NumberEntity   na = null, nb = null;
            OperatorEntity oa = null, ob = null;
            var            a      = Children.ElementAt(0).Eval();
            var            b      = Children.ElementAt(1).Eval();
            Entity         result = this;

            if ((a.IsNumberEntity(out na) && b.IsNumberEntity(out nb)))
            {
                return(EvalNumber(na, nb));
            }

            if (a.IsVariableEntity(out va) && b.IsVariableEntity(out vb))
            {
                return(EvalVariable(Name, va, vb));
            }

            if (Name == Constants.Operators.MUL)
            {
                return(EvalMultiplicationOperator(a, b));
            }

            if (Name == Constants.Operators.SUM || Name == Constants.Operators.SUB)
            {
                return(EvalSumOrSubOperator(Name, a, b));
            }

            switch (Name)
            {
            case Constants.Operators.MUL:
                return(a * b);

            case Constants.Operators.DIV:
                return(a / b);
            }

            return(null);
        }
 public bool IsNumberEntity(out NumberEntity result)
 {
     result = this as NumberEntity;
     return(result != null);
 }
        public IEnumerable <Entity> Solve(VariableEntity variable)
        {
            var dic      = new Dictionary <int, Entity>();
            var children = GetSumOrSubEntities(this);

            foreach (var child in children)
            {
                var monomial = ParseMonomial(child, variable);
                if (dic.ContainsKey(monomial.Key))
                {
                    dic[monomial.Key] += monomial.Value;
                }
                else
                {
                    dic.Add(monomial.Key, monomial.Value);
                }
            }

            if (dic.Count() == 1)
            {
                dic.Add(0, Number.Create(0));
            }

            var orders = dic.OrderBy(_ => _.Key).ToList();

            if (orders.Last().Value.IsNumberEntity(out NumberEntity last))
            {
                if (last.Number.Value < 0)
                {
                    for (var i = 0; i < orders.Count(); i++)
                    {
                        orders[i] = new KeyValuePair <int, Entity>(orders[i].Key, (Number.Create(-1) * orders[i].Value).Eval());
                    }
                }
            }

            if (orders.Count() == 2)
            {
                var expr = (Number.Create(-1) * orders.ElementAt(orders.ElementAt(0).Key).Value);
                if (orders.ElementAt(1).Key != 1)
                {
                    expr /= orders.ElementAt(orders.ElementAt(1).Key).Value;
                }

                var value = expr.Eval();
                var power = orders.ElementAt(1).Key;
                for (var i = 2; i <= power; i++)
                {
                    // value = System.Math.Sqrt(value);
                }

                return(new[] { value });
            }
            else if (orders.Count() == 3 && orders.ElementAt(2).Key == 2)
            {
                var a            = orders.ElementAt(2).Value;
                var b            = orders.ElementAt(1).Value;
                var c            = orders.ElementAt(0).Value;
                var discriminant = b * b - Number.Create(4) * a * c;
                var number       = discriminant.Eval() as NumberEntity;
                if (number != null)
                {
                    if (number.Number.Value == 0)
                    {
                        return(new Entity[] { (Number.Create(-1) * b) / Number.Create(2) * a });
                    }

                    var x1 = (Number.Create(-1) * b - MathEntity.Sqrt(number)) / Number.Create(2) * a;
                    var x2 = (Number.Create(-1) * b + MathEntity.Sqrt(number)) / Number.Create(2) * a;
                    return(new Entity[] { x1.Eval(), x2.Eval() });
                }
            }
            else if (orders.Last().Key == 3)
            {
                // http://www2.trinity.unimelb.edu.au/~rbroekst/MathX/Cubic%20Formula.pdf
                var          a     = orders.ElementAt(3).Value;
                var          b     = orders.ElementAt(2).Value;
                var          c     = orders.ElementAt(1).Value;
                var          d     = orders.ElementAt(0).Value;
                var          pi    = Number.Create(System.Math.PI);
                NumberEntity kos   = new NumberEntity(Number.Create(0));;
                NumberEntity r     = new NumberEntity(Number.Create(0));
                NumberEntity alpha = new NumberEntity(Number.Create(0));
                var          vt    = ((Number.Create(-1) * b) / Number.Create(3)).Eval();
                var          p     = ((c / a) - (b * b) / (Number.Create(3) * a * a)).Eval() as NumberEntity;
                var          q     = ((b * b * b / a / a / a / Number.Create(13.5)) + d / a - b * c / Number.Create(3) / a / a).Eval();
                var          del   = ((q * q) / Number.Create(4) + (p * p * p) / Number.Create(27)).Eval() as NumberEntity;
                if (del.Number.Value <= 0)
                {
                    if (p.Number.Value != 0)
                    {
                        kos = ((Number.Create(-1) * q) / Number.Create(2) / MathEntity.Sqrt(Number.Create(-1) * p * p * p / Number.Create(27))).Eval() as NumberEntity;
                        r   = MathEntity.Sqrt(Number.Create(-1) * p / Number.Create(3)).Eval() as NumberEntity;
                    }

                    if (kos.Number.Value == 1)
                    {
                        alpha = ((Number.Create(-1) * pi * (kos - Number.Create(1))) / Number.Create(2)).Eval() as NumberEntity;
                    }
                    else
                    {
                        alpha = MathEntity.Acos(kos).Eval() as NumberEntity;
                    }

                    var result = new List <Entity>();
                    for (int k = 0; k <= 2; k++)
                    {
                        var xk = (Number.Create(2) * r * MathEntity.Cos((alpha + Number.Create(2) * Number.Create(k) * pi) / Number.Create(3)) + vt).Eval() as NumberEntity;
                        result.Add(xk);
                    }

                    return(result.ToArray());
                }
                else
                {
                    throw new NotImplementedException();
                }
            }

            return(null);
        }
        private static Entity EvalSumOrSubOperator(string name, Entity a, Entity b)
        {
            VariableEntity va = null, vb = null;
            NumberEntity   na = null, nb = null;
            OperatorEntity oa = null, ob = null;

            // (x + x2) + 3
            // (x + x2) + x5
            if ((a.IsOperatorEntity(new string[] { Constants.Operators.SUM, Constants.Operators.SUB }, out oa) || b.IsOperatorEntity(new string[] { Constants.Operators.SUM, Constants.Operators.SUB }, out ob)) &&
                ((a.IsVariableEntity(out va) || b.IsVariableEntity(out vb)) ||
                 ((a.IsNumberEntity(out na) || b.IsNumberEntity(out nb)))))
            {
                var children = new List <Entity>();
                if (ob != null)
                {
                    children.Add(a);
                    if (name == Constants.Operators.SUB)
                    {
                        ob = (Number.Create(-1) * ob).Eval() as OperatorEntity;
                    }

                    var entities = GetSumOrSubEntities(ob);
                    children.AddRange(GetSumOrSubEntities(ob));
                }
                else
                {
                    children.AddRange(GetSumOrSubEntities(oa));
                    if (name == Constants.Operators.SUB)
                    {
                        b = (Number.Create(-1) * b).Eval();
                    }

                    children.Add(b);
                }

                var    variables      = children.Where(_ => _ is VariableEntity).GroupBy(_ => ((VariableEntity)_).Name + ((VariableEntity)_).Pow);
                var    numbers        = children.Where(_ => _ is NumberEntity);
                Entity variableEntity = null;
                foreach (var grp in variables)
                {
                    Entity subVariableEntity = null;
                    foreach (var variable in grp)
                    {
                        if (subVariableEntity == null)
                        {
                            subVariableEntity = variable;
                        }
                        else
                        {
                            subVariableEntity = (subVariableEntity + variable).Eval();
                        }
                    }

                    if (variableEntity == null)
                    {
                        variableEntity = subVariableEntity;
                    }
                    else
                    {
                        variableEntity = variableEntity + subVariableEntity;
                    }
                }

                Entity numberEntity = Number.Create(0);
                foreach (var number in numbers)
                {
                    numberEntity = (numberEntity + number).Eval();
                }

                return(variableEntity + numberEntity);
            }

            // a == 0 or b == 0
            bool isAEmpty = false, isBEmpty = false;

            if (a.IsNumberEntity(out na) && (isAEmpty = na.Number.Value == 0) || b.IsNumberEntity(out nb) && (isBEmpty = nb.Number.Value == 0))
            {
                return(isAEmpty ? b : a);
            }

            switch (name)
            {
            case Constants.Operators.SUM:
                return(a + b);

            default:
                return(a - b);
            }
        }
 private static Entity EvalMultiplicationOperator(VariableEntity va, NumberEntity ne)
 {
     return(va.Mul(ne));
 }