001/*
002 * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
003 * Copyright (C) 2006 - JScience (http://jscience.org/)
004 * All rights reserved.
005 * 
006 * Permission to use, copy, modify, and distribute this software is
007 * freely granted, provided that this notice is preserved.
008 */
009package org.jscience.mathematics.function;
010
011import java.io.Serializable;
012import java.util.Iterator;
013import java.util.List;
014
015import org.jscience.mathematics.structure.GroupAdditive;
016import org.jscience.mathematics.structure.GroupMultiplicative;
017
018import javolution.context.LocalContext;
019import javolution.context.ObjectFactory;
020import javolution.util.FastList;
021import javolution.lang.Realtime;
022import javolution.text.Text;
023import javolution.text.TextBuilder;
024
025/**
026 * <p> This abstract class represents a mapping between two sets such that
027 *     there is a unique element in the second set assigned to each element
028 *     in the first set.</p>
029 *     
030 * <p> Functions can be discrete or continuous and multivariate functions 
031 *     (functions with multiple variables) are also supported as illustrated 
032 *     below:[code]
033 *         // Defines local variables.
034 *         Variable.Local<Rational> varX = new Variable.Local<Rational>("x");
035 *         Variable.Local<Rational> varY = new Variable.Local<Rational>("y");
036 *         
037 *         // f(x, y) =  x² + x·y + 1;
038 *         Polynomial<Rational> x = Polynomial.valueOf(Rational.ONE, varX);
039 *         Polynomial<Rational> y = Polynomial.valueOf(Rational.ONE, varY);
040 *         Polynomial<Rational> fx_y = x.pow(2).plus(x.times(y)).plus(Rational.ONE);
041 *         System.out.println("f(x,y) = " + fx_y);
042 * 
043 *         // Evaluates f(1,0) 
044 *         System.out.println("f(1,0) = " + fx_y.evaluate(Rational.ONE, Rational.ZERO));
045 * 
046 *         // Calculates df(x,y)/dx
047 *         System.out.println("df(x,y)/dx = " + fx_y.differentiate(varX));
048 *          
049 *         > f(x,y) = [1/1]x^2 + [1/1]xy + [1/1]
050 *         > f(1,0) = 2/1
051 *         > df(x,y)/dx = [2/1]x + [1/1]y
052 *     [/code]</p>
053 *     
054 * <p> Functions are often given by formula (e.g. <code>f(x) = x²-x+1,
055 *     f(x,y)= x·y</code>) but the general function instance might tabulate
056 *     the values, solve an equation, etc.</p>
057 *     
058 * @author  <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
059 * @version 3.1, April 1, 2006
060 * @see <a href="http://en.wikipedia.org/wiki/Function_%28mathematics%29">
061 *      Wikipedia: Functions (mathematics)</a>
062 */
063public abstract class Function<X, Y> implements Serializable, Realtime  {
064
065    // TODO: Implements XMLSerializable.
066        
067    /**
068     * Default constructor. 
069     */
070    protected Function() {
071    }
072
073    /**
074     * Returns a lexically ordered list of the variables (or arguments)
075     * for this function (empty list for constant functions).
076     * 
077     * @return this function current unset variables (sorted).
078     */
079    public abstract List<Variable<X>> getVariables();
080
081    /**
082     * Evaluates this function using its {@link Variable variables} current
083     * values.
084     *
085     * @return the evaluation of this function.
086     * @throws FunctionException if any of this function's variable is not set.
087     */
088    public abstract Y evaluate();
089
090    /**
091     * Indicates if this function is equals to the specified object.
092     *
093     * @param obj the object to be compared with.
094     * @return <code>true</code> if this function and the specified argument
095     *         represent the same function; <code>false</code> otherwise.
096     */
097    public boolean equals(Object obj) {
098        return super.equals(obj);
099    }
100
101    /**
102     * Returns the hash code for this function (consistent with 
103     * {@link #equals(Object)}.
104     *
105     * @return this function hash code.
106     */
107    public int hashCode() {
108        return super.hashCode();
109    }
110
111    /**
112     * Retrieves the variable from this function having the specified 
113     * symbol (convenience method).
114     *
115     * @return the variable having the specified symbol or <code>null</code>
116     *         if none.
117     */
118    public final Variable<X> getVariable(String symbol) {
119        for (Variable<X> v : this.getVariables()) {
120            if (symbol.equals(v.getSymbol()))
121                return v;
122        }
123        return null;
124    }
125
126    /**
127     * Evaluates this function for the specified argument value
128     * (convenience method). The evaluation is performed 
129     * in a {@link javolution.context.LocalContext LocalContext} and 
130     * can safely be called upon functions with {@link Variable.Global global
131     * variables}.
132     *
133     * @param arg the single variable value used for the evaluation.
134     * @return the evaluation of this function.
135     * @throws FunctionException if <code>getVariables().size() != 1</code> 
136     */
137    public final Y evaluate(X arg) {
138        List<Variable<X>> vars = getVariables();
139        if (vars.size() != 1)
140            throw new FunctionException("This function is not monovariate");
141        Variable<X> x = vars.get(0);
142        X prev = x.get();
143        LocalContext.enter();
144        try {
145            x.set(arg);
146            return evaluate();
147        } finally {
148            x.set(prev);
149            LocalContext.exit();
150        }
151    }
152
153    /**
154     * Evaluates this function for the specified arguments values
155     * (convenience method). The evaluation is performed 
156     * in a {@link javolution.context.LocalContext LocalContext} and 
157     * can safely be called upon functions with {@link Variable.Global global
158     * variables}.
159     *
160     * @param args the variables values used for the evaluation.
161     * @return the evaluation of this function.
162     * @throws IllegalArgumentException 
163     *         if <code>args.length != getVariables().size())</code> 
164     */
165    public final Y evaluate(X... args) {
166        List<Variable<X>> vars = getVariables();
167        if (vars.size() != args.length)
168            throw new IllegalArgumentException("Found " + args.length
169                    + " arguments, but " + vars.size() + "required");
170        LocalContext.enter();
171        try {
172            return evaluate(args, vars, 0);
173        } finally {
174            LocalContext.exit();
175        }
176    }
177
178    private final Y evaluate(X[] args, List<Variable<X>> vars, int i) {
179        if (i < args.length) {
180            Variable<X> var = vars.get(i);
181            X prev = var.get();
182            var.set(args[i]);
183            try {
184                return evaluate(args, vars, i + 1);
185            } finally {
186                var.set(prev); // Restores previous variable value.
187            }
188        } else {
189            return evaluate();
190        }
191    }
192
193    /**
194     * Returns the composition of this function with the one specified.
195     *
196     * @param  that the function for which the return value is passed as
197     *         argument to this function.
198     * @return the function <code>(this o that)</code>
199     * @throws FunctionException if this function is not monovariate.
200     */
201    public <Z> Function<Z, Y> compose(Function<Z, X> that) {
202        if (getVariables().size() != 1)
203            throw new FunctionException("This function is not monovariate");
204        return Compose.newInstance(this, that);
205    }
206
207    /**
208     * Returns the first derivative of this function with respect to 
209     * the specified variable. 
210     * 
211     * @param  v the variable for which the derivative is calculated.
212     * @return <code>d[this]/dv</code>
213     * @see <a href="http://mathworld.wolfram.com/Derivative.html">
214     *      Derivative -- from MathWorld</a>
215     * @throws FunctionException if the derivative is undefined.
216     */
217    public Function<X, Y> differentiate(Variable<X> v) {
218        return Derivative.newInstance(this, v);
219    }
220
221    /**
222     * Returns an integral of this function with respect to 
223     * the specified variable. 
224     * 
225     * @param  v the variable for which the integral is calculated.
226     * @return <code>S[this·dv]</code>
227     * @see <a href="http://mathworld.wolfram.com/Integral.html">
228     *      Integral -- from MathWorld</a>
229     */
230    public Function<X, Y> integrate(Variable<X> v) {
231        return Integral.newInstance(this, v);
232    }
233
234    /**
235     * Returns the sum of this function with the one specified.
236     *
237     * @param  that the function to be added.
238     * @return <code>this + that</code>.
239     */
240    public Function<X, Y> plus(Function<X, Y> that) {
241        return Plus.newInstance(this, that);
242    }
243
244    /**
245     * Returns the difference of this function with the one specified.
246     *
247     * @param  that the function to be subtracted.
248     * @return <code>this - that</code>.
249     */
250    @SuppressWarnings("unchecked")
251    public Function<X, Y> minus(Function<X, Y> that) {
252        if (that instanceof GroupAdditive) {
253            Function thatOpposite = (Function) ((GroupAdditive) that)
254                    .opposite();
255            return this.plus(thatOpposite);
256        }
257        return Minus.newInstance(this, that);
258    }
259
260    /**
261     * Returns the product of this function with the one specified.
262     *
263     * @param  that the function multiplier.
264     * @return <code>this · that</code>.
265     */
266    public Function<X, Y> times(Function<X, Y> that) {
267        return Times.newInstance(this, that);
268    }
269
270    /**
271     * Returns the quotient of this function with the one specified.
272     * Evaluation of this function may raise an exception if the 
273     * function result is not a {
274     *
275     * @param  that the function divisor.
276     * @return <code>this / that</code>.
277     */
278    @SuppressWarnings("unchecked")
279    public Function<X, Y> divide(Function<X, Y> that) {
280        if (that instanceof GroupMultiplicative) {
281            Function thatInverse = (Function) ((GroupMultiplicative) that)
282                    .inverse();
283            return this.times(thatInverse);
284        }
285        return Divide.newInstance(this, that);
286    }
287
288    /**
289     * Returns this function raised at the specified exponent.
290     *
291     * @param  n the exponent.
292     * @return <code>this<sup>n</sup></code>
293     * @throws IllegalArgumentException if <code>n &lt;= 0</code>
294     */
295    public Function<X, Y> pow(int n) {
296        if (n <= 0)
297            throw new IllegalArgumentException("n: " + n
298                    + " zero or negative values not allowed");
299        Function<X, Y> pow2 = this;
300        Function<X, Y> result = null;
301        while (n >= 1) { // Iteration.
302            if ((n & 1) == 1) {
303                result = (result == null) ? pow2 : result.times(pow2);
304            }
305            pow2 = pow2.times(pow2);
306            n >>>= 1;
307        }
308        return result;
309    }
310    /**
311     * Returns the textual representation of this real-time object
312     * (equivalent to <code>toString</code> except that the returned value
313     * can be allocated from the local context space).
314     * 
315     * @return this object's textual representation.
316     */
317    public abstract Text toText();
318
319    /**
320     * Returns the text representation of this function as a 
321     * <code>java.lang.String</code>.
322     * 
323     * @return <code>toText().toString()</code>
324     */
325    public final String toString() {
326        return toText().toString();
327    }
328    
329    // Merges the variable from the specified function into a single table.
330    @SuppressWarnings("unchecked")
331    static final List merge(List left, List right) {
332        if (left.containsAll(right))
333            return left;
334        if (right.containsAll(left))
335            return right;
336        FastList result = FastList.newInstance();
337        Iterator iLeft = left.iterator();
338        Iterator iRight = right.iterator();
339        Variable l = null;
340        Variable r = null;
341        while (true) {
342            if (!iLeft.hasNext()) {
343                while (iRight.hasNext()) {
344                    result.add(iRight.next());
345                }
346                return result;
347            }
348            if (!iRight.hasNext()) {
349                while (iLeft.hasNext()) {
350                    result.add(iLeft.next());
351                }
352                return result;
353            }
354            l = (l == null) ? (Variable) iLeft.next() : l;
355            r = (r == null) ? (Variable) iRight.next() : r;
356            if (l == r) {
357                result.add(l);
358                l = null;
359                r = null;
360                continue;
361            }
362            int comp = l.getSymbol().compareTo(r.getSymbol());
363            if (comp < 0) {
364                result.add(l);
365                l = null;
366                continue;
367            }
368            if (comp > 0) {
369                result.add(r);
370                r = null;
371                continue;
372            }
373            throw new FunctionException("Duplicate symbol " + l.getSymbol());
374        }
375    }
376
377    // Function composition (default implementation).
378    private static final class Compose extends Function {
379
380        private static final ObjectFactory<Compose> FACTORY = new ObjectFactory<Compose>() {
381
382            protected Compose create() {
383                return new Compose();
384            }
385
386            protected void cleanup(Compose compose) {
387                compose._f = null;
388                compose._g = null;
389            }
390        };
391
392        private Function _f;
393
394        private Function _g;
395
396        @SuppressWarnings("unchecked")
397        public static <X, Y> Function<X, Y> newInstance(Function f, Function g) {
398            Compose compose = FACTORY.object();
399            compose._f = f;
400            compose._g = g;
401            return compose;
402        }
403
404        @Override
405        public List getVariables() {
406            return _g.getVariables();
407        }
408
409        @Override
410        @SuppressWarnings("unchecked")
411        public Object evaluate() {
412            return evaluate(_g.evaluate());
413        }
414
415        @SuppressWarnings("unchecked")
416        public Function differentiate(Variable v) {
417            // Chain rule: http://en.wikipedia.org/wiki/Chain_rule
418            Function fd = _f.differentiate(v);
419            Function gd = _g.differentiate(v);
420            return fd.compose(_g).times(gd);
421        }
422
423        public Text toText() {
424            return TextBuilder.newInstance().append('(').append(_f).append(')')
425                    .append('o').append('(').append(_g).append(')').toText();
426        }
427
428        @Override
429        public boolean equals(Object obj) {
430            if (!(obj instanceof Compose))
431                return false;
432            Compose that = (Compose) obj;
433            return this._f.equals(that._f) && this._g.equals(that._g);
434        }
435
436        @Override
437        public int hashCode() {
438            return _f.hashCode() + _g.hashCode();
439        }
440
441        private static final long serialVersionUID = 1L;
442
443    }
444
445    // Function derivative (default implementation).
446    private static final class Derivative extends Function {
447
448        private static final ObjectFactory<Derivative> FACTORY = new ObjectFactory<Derivative>() {
449
450            protected Derivative create() {
451                return new Derivative();
452            }
453
454            protected void cleanup(Derivative derivative) {
455                derivative._f = null;
456                derivative._v = null;
457            }
458        };
459
460        private Function _f;
461
462        private Variable _v;
463
464        @SuppressWarnings("unchecked")
465        public static <X, Y> Function<X, Y> newInstance(Function f, Variable v) {
466            Derivative derivative = FACTORY.object();
467            derivative._f = f;
468            derivative._v = v;
469            return derivative;
470        }
471
472        @Override
473        public List getVariables() {
474            return _f.getVariables();
475        }
476
477        @Override
478        public Object evaluate() {
479            throw new FunctionException("Derivative of " + _f + " undefined");
480        }
481
482        public Text toText() {
483            return TextBuilder.newInstance().append("d[").append(_f).append("]/d")
484            .append(_v.getSymbol()).toText();
485        }
486
487        @Override
488        public boolean equals(Object obj) {
489            if (!(obj instanceof Derivative))
490                return false;
491            Derivative that = (Derivative) obj;
492            return this._f.equals(that._f) && this._v.equals(that._v);
493        }
494
495        @Override
496        public int hashCode() {
497            return _f.hashCode() + _v.hashCode();
498        }
499
500        private static final long serialVersionUID = 1L;
501    }
502
503    // Function integral (default implementation).
504    private static final class Integral extends Function {
505
506        private static final ObjectFactory<Integral> FACTORY = new ObjectFactory<Integral>() {
507
508            protected Integral create() {
509                return new Integral();
510            }
511
512            protected void cleanup(Integral integral) {
513                integral._f = null;
514                integral._v = null;
515            }
516        };
517
518        private Function _f;
519
520        private Variable _v;
521
522        @SuppressWarnings("unchecked")
523        public static <X, Y> Function<X, Y> newInstance(Function f, Variable v) {
524            Integral integral = FACTORY.object();
525            integral._f = f;
526            integral._v = v;
527            return integral;
528        }
529
530        @Override
531        public List getVariables() {
532            return _f.getVariables();
533        }
534
535        @Override
536        public Object evaluate() {
537            throw new FunctionException("Integral of " + _f + " undefined");
538        }
539
540        public Text toText() {
541            return TextBuilder.newInstance().append("S[").append(_f).append("·d")
542            .append(_v.getSymbol()).append(']').toText();
543        }
544
545        @Override
546        public boolean equals(Object obj) {
547            if (!(obj instanceof Integral))
548                return false;
549            Integral that = (Integral) obj;
550            return this._f.equals(that._f) && this._v.equals(that._v);
551        }
552
553        @Override
554        public int hashCode() {
555            return _f.hashCode() + _v.hashCode();
556        }
557
558        private static final long serialVersionUID = 1L;
559    }
560
561    // Function addition (default implementation).
562    private static final class Plus extends Function {
563
564        private static final ObjectFactory<Plus> FACTORY = new ObjectFactory<Plus>() {
565
566            protected Plus create() {
567                return new Plus();
568            }
569
570            protected void cleanup(Plus plus) {
571                plus._f = null;
572                plus._g = null;
573            }
574        };
575
576        private Function _f, _g;
577
578        @SuppressWarnings("unchecked")
579        public static <X, Y> Function<X, Y> newInstance(Function f, Function g) {
580            Plus plus = FACTORY.object();
581            plus._f = f;
582            plus._g = g;
583            return plus;
584        }
585
586        @Override
587        public List getVariables() {
588            return merge(_f.getVariables(), _g.getVariables());
589        }
590
591        @SuppressWarnings("unchecked")
592        @Override
593        public Object evaluate() {
594            Object y2 = _g.evaluate();
595            Object y1 = _f.evaluate();
596            if (!(y1 instanceof GroupAdditive))
597                throw new FunctionException(y1.getClass()
598                        + " is not an additive group");
599
600            return ((GroupAdditive) y1).plus(y2);
601        }
602
603        @SuppressWarnings("unchecked")
604        @Override
605        public Function differentiate(Variable v) {
606            return _f.differentiate(v).plus(_g.differentiate(v));
607        }
608
609        @SuppressWarnings("unchecked")
610        @Override
611        public Function integrate(Variable v) {
612            return _f.integrate(v).plus(_g.integrate(v));
613        }
614
615        public Text toText() {
616            return TextBuilder.newInstance().append('(').append(_f).append(")")
617            .append('+').append('(').append(_g).append(')').toText();
618        }
619
620        @Override
621        public boolean equals(Object obj) {
622            if (!(obj instanceof Plus))
623                return false;
624            Plus that = (Plus) obj;
625            return this._f.equals(that._f) && this._g.equals(that._g);
626        }
627
628        @Override
629        public int hashCode() {
630            return _f.hashCode() + _g.hashCode();
631        }
632        
633        private static final long serialVersionUID = 1L;
634    }
635
636    // Function addition (default implementation).
637    private static final class Minus extends Function {
638
639        private static final ObjectFactory<Minus> FACTORY = new ObjectFactory<Minus>() {
640
641            protected Minus create() {
642                return new Minus();
643            }
644
645            protected void cleanup(Minus minus) {
646                minus._f = null;
647                minus._g = null;
648            }
649        };
650
651        private Function _f, _g;
652
653        @SuppressWarnings("unchecked")
654        public static <X, Y> Function<X, Y> newInstance(Function f, Function g) {
655            Minus minus = FACTORY.object();
656            minus._f = f;
657            minus._g = g;
658            return minus;
659        }
660
661        @Override
662        public List getVariables() {
663            return merge(_f.getVariables(), _g.getVariables());
664        }
665
666        @SuppressWarnings("unchecked")
667        @Override
668        public Object evaluate() {
669            Object y2 = _g.evaluate();
670            if (!(y2 instanceof GroupAdditive))
671                throw new FunctionException(y2.getClass()
672                        + " is not an additive group");
673            y2 = ((GroupAdditive) y2).opposite();
674
675            Object y1 = _f.evaluate();
676            if (!(y1 instanceof GroupAdditive))
677                throw new FunctionException(y1.getClass()
678                        + " is not an additive group");
679
680            return ((GroupAdditive) y1).plus(y2);
681        }
682
683        @SuppressWarnings("unchecked")
684        @Override
685        public Function differentiate(Variable v) {
686            return _f.differentiate(v).minus(_g.differentiate(v));
687        }
688
689        @SuppressWarnings("unchecked")
690        @Override
691        public Function integrate(Variable v) {
692            return _f.integrate(v).minus(_g.integrate(v));
693        }
694
695        public Text toText() {
696            return TextBuilder.newInstance().append('(').append(_f).append(")")
697            .append('-').append('(').append(_g).append(')').toText();
698        }
699
700        @Override
701        public boolean equals(Object obj) {
702            if (!(obj instanceof Minus))
703                return false;
704            Minus that = (Minus) obj;
705            return this._f.equals(that._f) && this._g.equals(that._g);
706        }
707
708        @Override
709        public int hashCode() {
710            return _f.hashCode() + _g.hashCode();
711        }
712        
713        private static final long serialVersionUID = 1L;
714    }
715
716    // Function multiplication (default implementation).
717    private static final class Times extends Function {
718
719        private static final ObjectFactory<Times> FACTORY = new ObjectFactory<Times>() {
720
721            protected Times create() {
722                return new Times();
723            }
724
725            protected void cleanup(Times times) {
726                times._f = null;
727                times._g = null;
728            }
729        };
730
731        private Function _f, _g;
732
733        @SuppressWarnings("unchecked")
734        public static <X, Y> Function<X, Y> newInstance(Function f, Function g) {
735            Times times = FACTORY.object();
736            times._f = f;
737            times._g = g;
738            return times;
739        }
740
741        @Override
742        public List getVariables() {
743            return merge(_f.getVariables(), _g.getVariables());
744        }
745
746        @SuppressWarnings("unchecked")
747        @Override
748        public Object evaluate() {
749            Object y2 = _g.evaluate();
750            Object y1 = _f.evaluate();
751            if (!(y1 instanceof GroupMultiplicative))
752                throw new FunctionException(y1.getClass()
753                        + " is not a multiplicative group");
754
755            return ((GroupMultiplicative) y1).times(y2);
756        }
757
758        @SuppressWarnings("unchecked")
759        @Override
760        public Function differentiate(Variable v) {
761            // Product rule: http://en.wikipedia.org/wiki/Product_rule
762            // (support for non-commutative multiplications).
763            // r' = d(f·g) = f'g + fg'
764            Function fd = _f.differentiate(v);
765            Function gd = _g.differentiate(v);
766            return fd.times(_g).plus(_f.times(gd));
767        }
768
769        public Text toText() {
770            return TextBuilder.newInstance().append('(').append(_f).append(")")
771            .append('·').append('(').append(_g).append(')').toText();
772        }
773
774        @Override
775        public boolean equals(Object obj) {
776            if (!(obj instanceof Times))
777                return false;
778            Times that = (Times) obj;
779            return this._f.equals(that._f) && this._g.equals(that._g);
780        }
781
782        @Override
783        public int hashCode() {
784            return _f.hashCode() + _g.hashCode();
785        }
786        
787        private static final long serialVersionUID = 1L;
788    }
789
790    // Function multiplication (default implementation).
791    private static final class Divide extends Function {
792
793        private static final ObjectFactory<Divide> FACTORY = new ObjectFactory<Divide>() {
794
795            protected Divide create() {
796                return new Divide();
797            }
798
799            protected void cleanup(Divide divide) {
800                divide._f = null;
801                divide._g = null;
802            }
803        };
804
805        private Function _f, _g;
806
807        @SuppressWarnings("unchecked")
808        public static <X, Y> Function<X, Y> newInstance(Function f, Function g) {
809            Divide divide = FACTORY.object();
810            divide._f = f;
811            divide._g = g;
812            return divide;
813        }
814
815        @Override
816        public List getVariables() {
817            return merge(_f.getVariables(), _g.getVariables());
818        }
819
820        @SuppressWarnings("unchecked")
821        @Override
822        public Object evaluate() {
823            Object y2 = _g.evaluate();
824            if (!(y2 instanceof GroupMultiplicative))
825                throw new FunctionException(y2.getClass()
826                        + " is not a multiplicative group");
827            y2 = ((GroupMultiplicative) y2).inverse();
828            Object y1 = _f.evaluate();
829            if (!(y1 instanceof GroupMultiplicative))
830                throw new FunctionException(y1.getClass()
831                        + " is not a multiplicative group");
832
833            return ((GroupMultiplicative) y1).times(y2);
834        }
835
836        @SuppressWarnings("unchecked")
837        @Override
838        public Function differentiate(Variable v) {
839            // Quotient rule: http://en.wikipedia.org/wiki/Quotient_rule
840            // with support for non-commutative multiplications.
841            // r = f/g,  rg = f, r'g + rg' = f' (produt rule)
842            // r' = (f' - rg')/g, r' = (f' - (f/g)g')/g
843            Function fd = _f.differentiate(v);
844            Function gd = _g.differentiate(v);
845            return fd.minus(_f.divide(_g).times(gd)).divide(_g);
846        }
847
848        public Text toText() {
849            return TextBuilder.newInstance().append('(').append(_f).append(")")
850            .append('/').append('(').append(_g).append(')').toText();
851        }
852
853        @Override
854        public boolean equals(Object obj) {
855            if (!(obj instanceof Divide))
856                return false;
857            Divide that = (Divide) obj;
858            return this._f.equals(that._f) && this._g.equals(that._g);
859        }
860
861        @Override
862        public int hashCode() {
863            return _f.hashCode() + _g.hashCode();
864        }
865
866        private static final long serialVersionUID = 1L;
867    }
868}