예제 #1
0
 private Expr _Substitute(NullExpr e)
 {
     return e;
 }
예제 #2
0
 public override Null Visit(NullExpr node)
 {
     context = null;
     node.computedType = new NullType();
     return null;
 }
예제 #3
0
 private Expr _Numericize(NullExpr e)
 {
     return e;
 }
예제 #4
0
        private Expr _Numericize(CompositeExpr e)
        {
            Expr[] args = new Expr[e.Args.Length];
            for (int i = 0; i < e.Args.Length; i++)
                if ((i != 0 || head(e) != WKSID.index) && !(i == 0 && e.Head == WellKnownSym.summation && e.Args.Length > 1))
                    args[i] = Numericize(e.Args[i]);
                else args[i] = e.Args[i];
            Expr val = Ag(e, 0);
            if (e.Head is WellKnownSym)
            {
                DoubleNumber dn1 = null;
                DoubleNumber dn2 = null;
                IntegerNumber in1 = null;
                IntegerNumber in2 = null;
                ComplexNumber cn1 = null;
                ComplexNumber cn2 = null;
                if (args.Length > 0)
                {
                    dn1 = args[0] as DoubleNumber;
                    cn1 = args[0] as ComplexNumber;
                    in1 = args[0] as IntegerNumber;
                }
                if (args.Length > 1)
                {
                    dn2 = args[1] as DoubleNumber;
                    cn2 = args[1] as ComplexNumber;
                    in2 = args[1] as IntegerNumber;
                }
                double d1 = 0;
                double d2 = 0;
                if (in2 != null) d2 = (double)in2.Num;
                if (in1 != null) d1 = (double)in1.Num;
                if (dn2 != null) d2 = dn2.Num;
                if (dn1 != null) d1 = dn1.Num;
                bool num1 = dn1 != null || in1 != null;
                bool num2 = dn2 != null || in2 != null;
                WKSID id = ((WellKnownSym)e.Head).ID;
                switch (id)
                {
                    case WKSID.im:
                        Trace.Assert(args.Length == 1);
                        if (args[0] is RealNumber) return 0.0;
                        else if (args[0] is ComplexNumber) return ((ComplexNumber)args[0]).Im;
                        break;
                    case WKSID.magnitude:
                        if (in1 != null) return in1.Num.abs();
                        if (dn1 != null) return Math.Abs(dn1.Num);
                        if (cn1 != null) return Numericize(new CompositeExpr(WellKnownSym.root, 2, new CompositeExpr(WellKnownSym.plus,
                             new CompositeExpr(WellKnownSym.power, cn1.Re, 2), new CompositeExpr(WellKnownSym.power, cn1.Im, 2))));
                        break;
                    case WKSID.minus:
                        Trace.Assert(args.Length == 1);
                        if (num1)
                            if (in1 != null) return new IntegerNumber(-in1.Num);
                            else return -d1;
                        else if (args[0] is ComplexNumber) return NMinus((ComplexNumber)args[0]);
                        else if (args[0] is ArrayExpr)
                        {
                            ArrayExpr ae = new ArrayExpr((Array)((ArrayExpr)args[0]).Elts.Clone());
                            foreach (int[] i in ae.Indices) ae[i] = Numericize(Minus(ae[i]));
                            if (!args[0].Annotations.Contains("Force Parentheses") || !args[0].Annotations["Force Parentheses"].Equals(0)) ae.Annotations["Force Parentheses"] = 1;
                            return ae;
                        }
                        break;
                    case WKSID.plus:
                        {
                            Trace.Assert(args.Length > 0);
                            if (args.Length == 1)
                            {
                                return args[0];
                            }
                            if (Array.TrueForAll(args, delegate(Expr a) { return a is ArrayExpr; }))
                            {
                                ArrayExpr[] aes = Array.ConvertAll<Expr, ArrayExpr>(args, delegate(Expr a) { return (ArrayExpr)a; });
                                int[] dims = aes[0].Dims;
                                bool isok = true;
                                for (int i = 1; isok && i < args.Length; i++)
                                {
                                    int[] dd = aes[i].Dims;
                                    if (dd.Length != dims.Length) isok = false;
                                    for (int j = 0; isok && j < dims.Length; j++) if (dims[j] != dd[j]) isok = false;
                                }
                                if (isok)
                                {
                                    ArrayExpr newae = new ArrayExpr((Array)aes[0].Elts.Clone());
                                    foreach (int[] ix in newae.Indices)
                                    {
                                        newae[ix] = Numericize(Plus(Array.ConvertAll<ArrayExpr, Expr>(aes, delegate(ArrayExpr ae) { return ae[ix]; })));
                                    }
                                    newae.Annotations["Force Parentheses"] = 1;
                                    return newae;
                                }
                            }
                            List<Expr> leftover = new List<Expr>();
                            double rsum = 0;
                            double isum = 0;
                            IntegerNumber risum = 0;
                            bool anyd = false, anyc = false, anyi = false;
                            foreach (Expr p in args)
                            {
                                DoubleNumber dn = p as DoubleNumber;
                                IntegerNumber inn = p as IntegerNumber;
                                ComplexNumber cn = p as ComplexNumber;
                                if (dn != null)
                                {
                                    if (anyi)
                                    {
                                        rsum = dn.Num + (double)risum.Num;
                                        anyi = false;
                                    }
                                    else
                                        rsum += dn.Num;
                                    anyd = true;
                                }
                                else if (inn != null)
                                {
                                    if (anyd)
                                        rsum += (double)inn.Num;
                                    else
                                    {
                                        risum = risum.Num + inn.Num;
                                        anyi = true;
                                    }
                                }
                                else if (cn != null)
                                {
                                    DoubleNumber red = cn.Re as DoubleNumber;
                                    DoubleNumber imd = cn.Im as DoubleNumber;
                                    if (red != null && imd != null)
                                    {
                                        if (anyi)
                                            rsum = red.Num + (double)risum.Num;
                                        else rsum += red.Num;
                                        isum += imd.Num;
                                        anyd = true;
                                        anyc = true;
                                        anyi = false;
                                    }
                                    else leftover.Add(p);
                                }
                                else leftover.Add(p);
                            }
                            Number rn = anyd ? (Number)new DoubleNumber(rsum) : (Number)risum;
                            Number n = anyc ? (Number)new ComplexNumber(rsum, isum) : (Number)rn;
                            if (leftover.Count == 0) return n;
                            else
                            {
                                if (anyd || anyi || anyc) leftover.Add(n);
                                return new CompositeExpr(e.Head, leftover.ToArray());
                            }
                        }
                    case WKSID.mod:
                        if (args.Length != 2) break;
                        if (in1 != null && in2 != null) return new IntegerNumber(in1.Num % in2.Num);
                        else if (in1 != null && dn2 != null) return Math.IEEERemainder(in1.Num.AsDouble(), dn2.Num);
                        else if (dn1 != null && in2 != null) return Math.IEEERemainder(dn1.Num, in2.Num.AsDouble());
                        else if (dn1 != null && dn2 != null) return Math.IEEERemainder(dn1.Num, dn2.Num);
                        break;
                    case WKSID.power:
                        if (args.Length < 2)
                            break;
                        Trace.Assert(args.Length == 2);
                        if (num1 && (d1 >= 0 || in2 != null) && num2)
                        {
                            double pow = Math.Pow(d1, d2);
                            return in1 != null && in2 != null && d2 > 0 ? (Expr)new IntegerNumber((int)pow) : (Expr)new DoubleNumber(pow);
                        }
                        else
                        {
                            if (num1) cn1 = new ComplexNumber(d1, 0.0);
                            if (num2) cn2 = new ComplexNumber(d2, 0.0);
                            if (cn1 != null && cn2 != null) return NPower(cn1, cn2);
                        }
                        if (num2 && d2 == 0)
                            return new DoubleNumber(1);
                        if (num2 && d2 == 1)
                            return args[0];
                        if (args[0] is ArrayExpr && args[1] == new LetterSym('T'))
                        {
                            // matrix transpose
                            // FIXME: actually, this should probably be turned into a wellknownsym "transpose" by parse2. Issue there is how to know T isn't being
                            // used as a variable?
                            ArrayExpr ae = (ArrayExpr)args[0];
                            if (ae.Elts.Rank == 1)
                            {
                                Expr[,] n = new Expr[ae.Elts.Length, 1];
                                for (int i = 0; i < ae.Elts.Length; i++)
                                {
                                    n[i, 0] = ae[i];
                                }
                                ae = new ArrayExpr(n);
                                ae.Annotations["Force Parentheses"] = 1;
                            }
                            else if (ae.Elts.Rank == 2)
                            {
                                int h = ae.Elts.GetLength(0);
                                int w = ae.Elts.GetLength(1);
                                Expr[,] n = new Expr[w, h];
                                for (int i = 0; i < h; i++)
                                {
                                    for (int j = 0; j < w; j++)
                                    {
                                        n[j, i] = ae[i, j];
                                    }
                                }
                                ae = new ArrayExpr(n);
                                ae.Annotations["Force Parentheses"] = 1;
                                return ae;
                            }
                        }
                        break;
                    case WKSID.re:
                        Trace.Assert(args.Length == 1);
                        if (num1) return args[0];
                        else if (cn1 != null) return cn1.Re;
                        break;
                    case WKSID.times:
                        Trace.Assert(args.Length > 0);
                        if (args.Length == 1)
                        {
                            return args[0];
                        }
                        else
                        {
                            List<Expr> leftover = new List<Expr>();
                            int start = 0;
                            while (start < args.Length)
                            {
                                int end;
                                bool isarray = args[start] is ArrayExpr;
                                for (end = start + 1; end < args.Length; end++)
                                {
                                    if (isarray != (args[end] is ArrayExpr)) break;
                                }
                                leftover.AddRange(isarray ? NMultiplyArrays(args, start, end) : NMultiplyScalars(args, start, end));
                                start = end;
                            }
                            if (leftover.Count == 1)
                            {
                                return leftover[0];
                            }
                            else
                            {
                                leftover = this.NMultipyAll(args, e);
                                if (leftover.Count == 1)
                                    return leftover[0];
                                else
                                    return new CompositeExpr(e.Head, leftover.ToArray());
                            }
                            //original code before matrix scalar computations
                            //if(leftover.Count == 1) return leftover[0];
                            //else
                            //return new CompositeExpr(e.Head, leftover.ToArray());
                        }

                    case WKSID.divide:
                        Trace.Assert(args.Length == 1);
                        if (num1) return 1 / d1;
                        else if (args[0] is ComplexNumber) return NReciprocal((ComplexNumber)args[0]);
                        break;
                    case WKSID.ln:
                        Trace.Assert(args.Length == 1);
                        if (num1)
                        {
                            if (d1 >= 0) return Math.Log(d1);
                            return NLog(d1);
                        }
                        else if (args[0] is ComplexNumber) return NLog((ComplexNumber)args[0]);
                        break;
                    case WKSID.log: /* log takes base then value to take the logarithm of */
                        if (args.Length == 1)
                        {
                            dn2 = dn1;
                            in2 = in1;
                            cn2 = cn1;
                            d2 = d1;
                            num2 = num1;
                            d1 = 10;
                            dn1 = 10;
                            in1 = null;
                            cn1 = null;
                            num1 = true;
                        }
                        if (num1 && num2)
                        {
                            if (d1 >= 0 && num2 && d2 >= 0)
                                return Math.Log(d2, d1);
                            else return double.NaN;
                        }
                        else
                        {
                            if (num1) cn1 = new ComplexNumber(d1, 0.0);
                            if (num2) cn2 = new ComplexNumber(d2, 0.0);
                            if (cn1 != null && cn2 != null) return NTimes(NLog(cn2), NReciprocal(NLog(cn1)));
                        }
                        break;
                    case WKSID.root: /* takes root number (eg 2 for square root), value to take the root of */
                        Trace.Assert(args.Length == 2);
                        if (num1 && num2 && d2 >= 0) return Math.Pow(d2, 1 / d1);
                        else
                        {
                            if (num1) cn1 = new ComplexNumber(d1, 0.0);
                            if (num2) cn2 = new ComplexNumber(d2, 0.0);
                            if (cn1 != null && cn2 != null) return NPower(cn2, NReciprocal(cn1));
                        }
                        if (head(args[1]) == WKSID.power)
                            return Numericize(Power(Ag(args[1], 0), Mult(Ag(args[1], 1), Divide(args[0]))));
                        break;
                    case WKSID.index:
                        {
                            bool didnumericize = false;
                            if (!(args[0] is ArrayExpr))
                            {
                                args[0] = Numericize(args[0]);
                                didnumericize = true;
                            }
                            ArrayExpr aex = null, aix = null;
                            if (!IsArrayIndex(e, ref aex, ref aix))
                            {
                                if (!didnumericize) args[0] = Numericize(args[0]);
                                break;
                            }
                            int[] ix = ConvertToInd(aix, ExprToInd);
                            if (ix == null)
                            {
                                if (!didnumericize) args[0] = Numericize(args[0]);
                                break;
                            }
                            return Numericize(aex[ix]);
                        }
                    case WKSID.sin:
                        Trace.Assert(args.Length == 1);
                        if (head(val) == WKSID.times && Ag(val, 1) == _degree)
                            return Numericize(new CompositeExpr(WellKnownSym.sin, Mult(WellKnownSym.pi, Num(Mult(Ag(val, 0), Divide(180))))));
                        if (num1) return Math.Sin(d1);
                        else if (cn1 != null) return NSin(cn1);
                        break;
                    case WKSID.cos:
                        Trace.Assert(args.Length == 1);
                        if (head(val) == WKSID.times && Ag(val, 1) == _degree)
                            return Numericize(new CompositeExpr(WellKnownSym.cos, Mult(WellKnownSym.pi, Num(Mult(Ag(val, 0), Divide(180))))));
                        if (num1) return Math.Cos(d1);
                        else if (cn1 != null) return NCos(cn1);
                        break;
                    case WKSID.tan:
                        Trace.Assert(args.Length == 1);
                        if (head(val) == WKSID.times && Ag(val, 1) == _degree)
                            return Numericize(new CompositeExpr(WellKnownSym.tan, Mult(WellKnownSym.pi, Num(Mult(Ag(val, 0), Divide(180))))));
                        if (num1) return Math.Tan(d1);
                        else if (cn1 != null) return NTan(cn1);
                        break;
                    case WKSID.sec:
                        Trace.Assert(args.Length == 1);
                        if (head(val) == WKSID.times && Ag(val, 1) == _degree)
                            return Numericize(new CompositeExpr(WellKnownSym.sec, Mult(WellKnownSym.pi, Num(Mult(Ag(val, 0), Divide(180))))));
                        if (num1) return 1 / Math.Cos(d1);
                        else if (cn1 != null) return NReciprocal(NCos(cn1));
                        break;
                    case WKSID.csc:
                        Trace.Assert(args.Length == 1);
                        if (head(val) == WKSID.times && Ag(val, 1) == _degree)
                            return Numericize(new CompositeExpr(WellKnownSym.csc, Mult(WellKnownSym.pi, Num(Mult(Ag(val, 0), Divide(180))))));
                        if (num1) return 1 / Math.Sin(d1);
                        else if (args[0] is ComplexNumber) return NReciprocal(NSin(cn1));
                        break;
                    case WKSID.cot:
                        Trace.Assert(args.Length == 1);
                        if (head(val) == WKSID.times && Ag(val, 1) == _degree)
                            return Numericize(new CompositeExpr(WellKnownSym.cot, Mult(WellKnownSym.pi, Num(Mult(Ag(val, 0), Divide(180))))));
                        if (num1) return 1 / Math.Tan(d1);
                        if (cn1 != null) return NReciprocal(NTan(cn1));
                        break;
                    case WKSID.asin:
                        Trace.Assert(args.Length == 1);
                        if (num1) return Math.Asin(d1);
                        if (cn1 != null) return NArcSin(cn1);
                        break;
                    case WKSID.acos:
                        Trace.Assert(args.Length == 1);
                        if (head(val) == WKSID.times && Ag(val, 1) == _degree)
                            return Numericize(new CompositeExpr(WellKnownSym.acos, Mult(WellKnownSym.pi, Num(Mult(Ag(val, 0), Divide(180))))));
                        if (num1) return Math.Acos(d1);
                        if (cn1 != null) return NArcCos(cn1);
                        break;
                    case WKSID.atan:
                        Trace.Assert(args.Length == 1);
                        if (num1) return Math.Atan(d1);
                        if (cn1 != null) return NArcTan(cn1);
                        break;
                    case WKSID.asec:
                        Trace.Assert(args.Length == 1);
                        if (num1) return Math.Acos(1 / d1);
                        if (cn1 != null) return NArcCos(NReciprocal(cn1));
                        break;
                    case WKSID.acsc:
                        Trace.Assert(args.Length == 1);
                        if (num1) return Math.Asin(1 / d1);
                        if (cn1 != null) return NArcSin(NReciprocal(cn1));
                        break;
                    case WKSID.acot:
                        Trace.Assert(args.Length == 1);
                        if (num1) return Math.Atan(1 / d1);
                        if (cn1 != null) return NArcTan(NReciprocal(cn1));
                        break;
                    case WKSID.sinh:
                        Trace.Assert(args.Length == 1);
                        if (num1) return Math.Sinh(d1);
                        if (cn1 != null) return NSinH(cn1);
                        break;
                    case WKSID.cosh:
                        Trace.Assert(args.Length == 1);
                        if (num1) return Math.Cosh(d1);
                        if (cn1 != null) return NCosH(cn1);
                        break;
                    case WKSID.tanh:
                        Trace.Assert(args.Length == 1);
                        if (num1) return Math.Tanh(d1);
                        if (cn1 != null) return NTanH(cn1);
                        break;
                    case WKSID.sech:
                        Trace.Assert(args.Length == 1);
                        if (num1) return 1 / Math.Cosh(d1);
                        if (cn1 != null) return NReciprocal(NCosH(cn1));
                        break;
                    case WKSID.csch:
                        Trace.Assert(args.Length == 1);
                        if (num1) return 1 / Math.Sinh(d1);
                        if (cn1 != null) return NReciprocal(NSinH(cn1));
                        break;
                    case WKSID.coth:
                        Trace.Assert(args.Length == 1);
                        if (num1) return 1 / Math.Tanh(d1);
                        if (cn1 != null) return NReciprocal(NTanH(cn1));
                        break;
                    case WKSID.asinh:
                    case WKSID.acosh:
                    case WKSID.atanh:
                    case WKSID.asech:
                    case WKSID.acsch:
                    case WKSID.acoth:
                        /* C# library doesn't contain these functions */
                        break;
                    case WKSID.factorial:
                        Trace.Assert(args.Length == 1);
                        if (in1 != null && in1.Num >= 0) return Factorial(in1.Num);
                        break;
                    case WKSID.summation:
                        Trace.Assert(args.Length > 0 && args.Length < 4);
                        if (args.Length == 3 && num2 && e.Args[0] is CompositeExpr && !(e.Args[2] is NullExpr))
                        {
                            CompositeExpr ce = e.Args[0] as CompositeExpr;
                            Expr key = new NullExpr();
                            d1 = 0;
                            if (ce != null && ce.Head == WellKnownSym.equals && (ce.Args[0] is LetterSym || ce.Args[0] is WellKnownSym))
                            {
                                key = ce.Args[0].Clone();
                                Expr start = Numericize(ce.Args[1]);
                                IntegerNumber sinn = start as IntegerNumber;
                                DoubleNumber sdn = start as DoubleNumber;
                                d1 = (sinn != null) ? (double)sinn.Num : sdn != null ? sdn.Num : double.NaN;
                            }
                            Expr res = new IntegerNumber(0);
                            for (int d = (int)d1; d1 <= d2 && d <= (int)d2; d++)
                            {
                                Expr newB = (Expr)e.Args[2].Clone();
                                newB = Numericize(_Substitute(newB, key, d));
                                res = Plus(res, newB);
                                res = Numericize(_Simplify(res));
                            }
                            return res;
                        }
                        break;
                }
            }
            return new CompositeExpr(Numericize(e.Head), args);
        }
예제 #5
0
 public Expr Num(Expr e)
 {
     if (e is IntegerNumber)
         return e;
     IntegerNumber num = 0;
     IntegerNumber den = 1;
     Expr accum = null;
     switch (head(e))
     {
         case WKSID.times:
             bool numIsNum = false;
             List<Expr> fargs1 = flattenMults(e as CompositeExpr);
             List<Expr> fargs = new List<Expr>();
             for (int i = 0; i < fargs1.Count; i++)
                 fargs.Add(Num(fargs1[i]));
             List<Expr> additions = new List<Expr>();
             List<Expr> others = new List<Expr>();
             foreach (Expr t in fargs)
             {
                 if (head(t) == WKSID.plus)
                     additions.Add(t);
                 else others.Add(t);
             }
             Expr additiveAccum = null;
             foreach (Expr t in fargs)
             { // compute fraction terms
                 Expr tval = Num(t);
                 if (tval == WellKnownSym.infinity) // mult by inf -> inf
                     return WellKnownSym.infinity;
                 DivideExpr div = new DivideExpr(tval);
                 PowerExpr pow = new PowerExpr(tval);
                 if (tval is IntegerNumber) { num.Num = (numIsNum ? num.Num : 1) * (tval as IntegerNumber).Num; numIsNum = true; }
                 else if (pow.OK && pow.PowerInt && pow.IPower < 0) den.Num *= pow.IPower;
                 else if (div.OK && div.DivisorInt) den.Num *= div.IDivisor;
                 else if (head(tval) == WKSID.times && (head(Ag(tval, 0)) == WKSID.plusminus || head(Ag(tval, 1)) == WKSID.plusminus))
                     if (additiveAccum == null)
                         additiveAccum = tval;
                     else additiveAccum = Mult(additiveAccum, tval);
                 else if (head(tval) == WKSID.times && Ag(tval, 0) is IntegerNumber)
                 {
                     DivideExpr dexp = new DivideExpr(Ag(tval, 1));
                     if (dexp.OK && dexp.DivisorInt)
                     {                   // keep integer fractions, leave others unsimplified
                         if (den.Num == dexp.IDivisor)
                         {
                             num.Num *= (Ag(tval, 0) as IntegerNumber).Num;
                             numIsNum = true;
                         }
                         else
                         {
                             num.Num = (Ag(tval, 0) as IntegerNumber).Num * num.Num;
                             den.Num *= dexp.IDivisor;
                             numIsNum = true;
                         }
                     }
                     else if (accum == null)
                         accum = tval;
                     else accum = Mult(accum, tval);
                 }
                 else if (accum == null)
                     accum = tval;
                 else accum = Mult(accum, tval);
             }
             if (den.Num == 0 && num.Num == 0) return double.NaN;
             if (den.Num == 0) return WellKnownSym.infinity; // divide by zero -> infinity
             if (num.Num == 0 && numIsNum) return 0; // terminate early if we're multiplying by 0
             Expr fraction = null;
             if (numIsNum && (den.Num != 1 || num.Num != 1))
             {
                 if ((double)num.Num / (double)den.Num == (int)num.Num / (int)den.Num) // convert frac to integer if possible
                     fraction = (int)(num.Num / den.Num);
                 else if ((double)den.Num / (double)num.Num == (int)(den.Num / num.Num)) // reduce numerator if possible
                     fraction = Divide((int)(den.Num / num.Num));
                 else fraction = Mult(num, Divide(den)); // fraction
             }
             else if (den.Num != 1)
                 fraction = Divide(den);
             if ((fraction == null || (fraction is IntegerNumber && (fraction as IntegerNumber).Num == 1)))
                 if (accum != null && additiveAccum != null)
                     return Mult(accum, additiveAccum);
                 else if (accum != null)
                     return accum;
                 else if (additiveAccum != null)
                     return additiveAccum;
             if (fraction != null && accum == null && additiveAccum == null)
                 return fraction;
             if (fraction == null && accum == null && additiveAccum == null)
                 return 1;
             if (accum == null)
                 return Plus(fraction, additiveAccum);
             else if (additiveAccum == null)
             {
                 if (head(accum) == WKSID.plus)
                 {
                     List<Expr> plusterms = new List<Expr>();
                     for (int i = 0; i < Args(accum).Length; i++)
                         plusterms.Add(Num(Mult(Args(accum)[i], fraction)));
                     return Plus(plusterms.ToArray());
                 }
                 return Mult(fraction, accum);
             }
             return Plus(Mult(fraction, accum), additiveAccum);
         case WKSID.factorial:
             {
                 Expr arg = Num(Ag(e, 0));
                 if (arg is IntegerNumber && ((IntegerNumber)arg).Num > 0) return Factorial(((IntegerNumber)arg).Num);
                 else return new CompositeExpr(WellKnownSym.factorial, arg);
             }
         case WKSID.divide:
             return Num(Power(Ag(e, 0), -1));
         case WKSID.minus:
             Expr term = Num(Ag(e, 0));
             if (term == WellKnownSym.infinity) return WellKnownSym.infinity;
             if (term is IntegerNumber) return (int)-(term as IntegerNumber).Num;
             if (term is DoubleNumber) return (double)-(term as DoubleNumber).Num;
             switch (head(term))
             {
                 case WKSID.times: // - (a 4 c) ->  a -4 c
                     List<Expr> rem = new List<Expr>();
                     bool flipped = false;
                     foreach (Expr m in Args(term))
                         if (!flipped && m is IntegerNumber)
                         {
                             flipped = true;
                             rem.Add((int)-(m as IntegerNumber).Num);
                         }
                         else rem.Add(m);
                     if (flipped)
                         return Mult(rem.ToArray());
                     break;
                 case WKSID.divide:
                     DivideExpr dexp = new DivideExpr(term);
                     if (dexp.OK && dexp.DivisorInt)
                         return Divide((int)-dexp.IDivisor);
                     break;
                 case WKSID.plus:
                     return Num(Mult(-1, term));
             }
             return Minus(term);
         case WKSID.mod:
             {
                 Expr a = Num(Ag(e, 0));
                 Expr b = Num(Ag(e, 1));
                 IntegerNumber ia = a as IntegerNumber;
                 IntegerNumber ib = b as IntegerNumber;
                 DoubleNumber da = a as DoubleNumber;
                 DoubleNumber db = b as DoubleNumber;
                 if (ia != null && ib != null) return ia.Num % ib.Num;
                 else if (ia != null && db != null) return Math.IEEERemainder(ia.Num.AsDouble(), db.Num);
                 else if (da != null && ib != null) return Math.IEEERemainder(da.Num, ib.Num.AsDouble());
                 else if (da != null && db != null) return Math.IEEERemainder(da.Num, db.Num);
                 else return new CompositeExpr(WellKnownSym.mod, a, b);
             }
         case WKSID.power:
             {
                 Expr bas = Num(Ag(e, 0));
                 Expr pow = Num(Ag(e, 1));
                 if (head(bas) == WKSID.times)
                 { // distribute (ab)^x -> a^x b^x
                     List<Expr> nargs = new List<Expr>();
                     foreach (Expr t in Args(bas))
                         nargs.Add(Power(t, pow));
                     return Num(Mult(nargs.ToArray()));
                 }
                 if (bas is IntegerNumber && pow is IntegerNumber)
                 { // compute a^b
                     BigInt basI = (bas as IntegerNumber).Num;
                     BigInt powI = (pow as IntegerNumber).Num;
                     Expr powNum = new NullExpr();
                     try
                     {
                         if (powI == -1)
                             powNum = bas;
                         else powNum = Math.Pow((int)(bas as IntegerNumber), Math.Abs((int)(pow as IntegerNumber)));
                     }
                     catch (Exception)
                     {
                         powNum = new IntegerNumber((int)FSBigInt.Pow(basI.Num, (int)FSBigInt.Abs(powI.Num)));
                     }
                     if ((powNum is DoubleNumber) && (int)(powNum as DoubleNumber).Num == (powNum as DoubleNumber).Num)
                         powNum = (int)((powNum as DoubleNumber).Num);
                     if (powI < 0)
                         return Divide(powNum);
                     return powNum;
                 }
                 if (pow is IntegerNumber)
                 {
                     BigInt powI = (pow as IntegerNumber).Num;
                     if (powI == 1) return bas;             // x^1 -> x
                     if (powI == 0) return 1;               // x^0 -> 1
                 }
                 DivideExpr dexp = new DivideExpr(pow);  // XXX- hack - x^(a/b) sometimes is an int need symbolic test
                 if (bas is IntegerNumber && dexp.OK && dexp.DivisorInt)
                 {
                     int neg = ((int)(dexp.IDivisor / 2) == ((int)dexp.IDivisor) / 2 && (bas as IntegerNumber).Num < 0) ? -1 : 1;
                     double pd = Math.Pow(neg * (int)(bas as IntegerNumber).Num, 1.0 / (int)dexp.IDivisor);
                     if (Math.Abs(pd - Math.Round(pd)) < 1e-15)
                     {
                         int p = (int)Math.Round(pd);
                         if (neg < 0)
                         {
                             int n = (int)dexp.IDivisor;
                             // (-256)^(1/8) -> -2i
                             // (-128)^(1/7)-> -2
                             // (-64)^(1/6) -> +-2i
                             // (-32)^(1/5) -> -2
                             // (-16)^(1/4) -> 2+2i
                             // (-8)^(1/3) -> -2
                             // (-4)^(1/2) -> 2i
                             if ((n + 1) / 2 == (n + 1) / 2.0) // odd fraction power is -p
                                 return -p;
                             if (n == 2)               // sqrt is p*imaginary
                                 return p == 1 ? (Expr)WellKnownSym.i : Mult(p, WellKnownSym.i);
                             Expr re = Num(Mult(p, Num(new CompositeExpr(WellKnownSym.cos, Mult(WellKnownSym.pi, Divide(n))))));
                             Expr im = Num(Mult(p, new CompositeExpr(WellKnownSym.sin, Mult(WellKnownSym.pi, Divide(n)))));
                             if (re is RealNumber && im is RealNumber)
                                 return new ComplexNumber(re as RealNumber, im as RealNumber);
                             return Mult(Num(Power(Minus(bas), Divide(n))), Power(-1, Divide(n)));
                         }
                         return (int)p;
                     }
                     int mult = 1;
                     BigInt basVal = (bas as IntegerNumber).Num;
                     while (dexp.IDivisor == 2 && (basVal >= 4 || basVal <= -4) && ((int)basVal / 4.0) == (double)(basVal / 4))
                     {
                         mult *= 2;
                         basVal = basVal / 4;
                     }
                     while (dexp.IDivisor == 2 && (basVal >= 9 || basVal <= -9) && ((int)basVal / 9.0) == (double)(basVal / 9))
                     {
                         mult *= 3;
                         basVal = basVal / 9;
                     }
                     while (dexp.IDivisor == 2 && (basVal >= 25 || basVal <= -25) && ((int)basVal / 25.0) == (double)(basVal / 25))
                     {
                         mult *= 5;
                         basVal = basVal / 25;
                     }
                     while (dexp.IDivisor == 2 && (basVal >= 49 || basVal <= -49) && ((int)basVal / 49.0) == (double)(basVal / 49))
                     {
                         mult *= 7;
                         basVal = basVal / 49;
                     }
                     if (mult != 1)
                         if (basVal != 1)
                             return Mult(mult, Power(new IntegerNumber(basVal), pow));
                         else return new IntegerNumber(basVal);
                 }
                 if (head(bas) == WKSID.divide) return Num(Divide(Power(Ag(bas, 0), pow))); // (1/x)^a -> x^(-a)bas
                 if (head(bas) == WKSID.power) return Num(Power(Ag(bas, 0), Mult(Ag(bas, 1), pow))); // (x^a)^b ->  x^(a*b)
                 RealNumber bnum = bas as RealNumber, pnum = pow as RealNumber;
                 if (bnum != null && pnum != null)
                 {
                     double b = (bnum is IntegerNumber) ? (double)((bnum as IntegerNumber).Num) : (bnum as DoubleNumber).Num;
                     double p = (pnum is IntegerNumber) ? (double)((pnum as IntegerNumber).Num) : (pnum as DoubleNumber).Num;
                     double r = Math.Pow(b, p);
                     if (Math.Abs(r - Math.Round(r)) < 1e-15)
                         return (int)Math.Round(r);
                     return r;
                 }
                 return Power(bas, pow);
             }
         case WKSID.root: // nth root (x) -> x ^(1/n)
             return Num(Power(Ag(e, 0), Divide(Ag(e, 1))));
         case WKSID.acos:
             {
                 Expr val = Num(Ag(e, 0));
                 return new CompositeExpr(WellKnownSym.acos, val);
             }
         case WKSID.magnitude:
             {
                 Expr val = Num(Ag(e, 0));
                 if (val is IntegerNumber)
                     return (val as IntegerNumber).Num.abs();
                 else if (val is DoubleNumber)
                     return Math.Abs((val as DoubleNumber).Num);
                 else return new CompositeExpr(WellKnownSym.magnitude, val);
             }
         case WKSID.asin:
             {
                 Expr val = Num(Ag(e, 0));
                 return new CompositeExpr(WellKnownSym.asin, val);
             }
         case WKSID.atan:
             {
                 Expr val = Num(Ag(e, 0));
                 return new CompositeExpr(WellKnownSym.atan, val);
             }
         case WKSID.asec:
             {
                 Expr val = Num(Ag(e, 0));
                 return new CompositeExpr(WellKnownSym.asec, val);
             }
         case WKSID.acsc:
             {
                 Expr val = Num(Ag(e, 0));
                 return new CompositeExpr(WellKnownSym.acsc, val);
             }
         case WKSID.acot:
             {
                 Expr val = Num(Ag(e, 0));
                 return new CompositeExpr(WellKnownSym.acot, val);
             }
         case WKSID.sec:
             {
                 Expr val = Num(Ag(e, 0));
                 return new CompositeExpr(WellKnownSym.sec, val);
             }
         case WKSID.csc:
             {
                 Expr val = Num(Ag(e, 0));
                 return new CompositeExpr(WellKnownSym.csc, val);
             }
         case WKSID.cot:
             {
                 Expr val = Num(Ag(e, 0));
                 return new CompositeExpr(WellKnownSym.cot, val);
             }
         case WKSID.cos:
             {
                 Expr val = Num(Ag(e, 0));
                 if (val is IntegerNumber && (val as IntegerNumber).Num == 0) //cos(0) -> 1
                     return 1;
                 return new CompositeExpr(WellKnownSym.cos, val);
             }
         case WKSID.index:
             {
                 ArrayExpr ae = null, ai = null;
                 if (!IsArrayIndex(e, ref ae, ref ai)) return e;
                 int[] inds = ConvertToInd(ai, delegate(Expr ee) { return ExprToInd(Numericize(ee)); });
                 if (inds == null) return e;
                 return Num(ae[inds]);
             }
         case WKSID.sin:
             {
                 Expr val = Num(Ag(e, 0));
                 if ((val is IntegerNumber && (val as IntegerNumber).Num == 0)) //sin(0) -> 0
                     return 0;
                 return new CompositeExpr(WellKnownSym.sin, val);
             }
         case WKSID.tan:
             {
                 Expr val = Num(Ag(e, 0));
                 if ((val is IntegerNumber && (val as IntegerNumber).Num == 0)) //tan(0) -> 0
                     return 0;
                 return new CompositeExpr(WellKnownSym.tan, val);
             }
         case WKSID.plus:
             num.Num = 0;
             foreach (Expr t in Args(e))
             {
                 Expr tval = Num(t);
                 if (tval is WellKnownSym && (tval as WellKnownSym).ID == WKSID.infinity) // add infinity -> infinity
                     return WellKnownSym.infinity;
                 if (tval is IntegerNumber)
                 {
                     num.Num += den.Num * (BigInt)tval; // accumulate numerator
                     continue;
                 }
                 if (head(tval) == WKSID.divide && Ag(tval, 0) is IntegerNumber)
                 { // accumulate divisor (& numerator)
                     BigInt oldden = den.Num;
                     BigInt newden = (BigInt)Ag(tval, 0);
                     num.Num *= newden;
                     den.Num *= newden;
                     num.Num += oldden;
                     continue;
                 }
                 if (head(tval) == WKSID.times && Ag(tval, 0) is IntegerNumber)
                 {  // accumulate fraction
                     DivideExpr dexp = new DivideExpr(Ag(tval, 1));
                     if (dexp.OK && dexp.DivisorInt)
                     {                   // keep integer fractions, leave others unsimplified
                         BigInt oldden = den.Num;
                         BigInt newnum = (BigInt)Ag(tval, 0);
                         BigInt newden = dexp.IDivisor;
                         if (oldden == newden)
                         {
                             num.Num += newnum;
                         }
                         else
                         {
                             num.Num *= newden;
                             den.Num *= newden;
                             num.Num += oldden * newnum;
                         }
                         continue;
                     }
                 }
                 if (accum == null)
                     accum = tval;
                 else
                     accum = Plus(accum, tval);
             }
             if (num.Num == 0)
             {
                 if (accum != null)
                     return accum;
                 return 0;
             }
             Expr frac = ((double)num.Num / (double)den.Num == (int)(num.Num / den.Num)) ? (Expr)(int)(num.Num / den.Num) :
                                                                                       (Expr)Mult(num, Divide(den));
             return accum == null ? frac : Plus(frac, accum);
         default:
             if (e is CompositeExpr)
             {
                 List<Expr> args = new List<Expr>();
                 foreach (Expr a in Args(e))
                     args.Add(Num(a));
                 return new CompositeExpr((e as CompositeExpr).Head.Clone(), args.ToArray());
             }
             break;
     }
     return e;
 }
예제 #6
0
 private Expr _Canonicalize(NullExpr e)
 {
     return e;
 }
예제 #7
0
 public override string Visit(NullExpr e) => "null";
예제 #8
0
 protected override Box __Translate(NullExpr e)
 {
     return(new NullBox());
 }
예제 #9
0
 public virtual T Visit(NullExpr e) => default(T);