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: */
009: package org.jscience.mathematics.function;
010:
011: import java.io.Serializable;
012: import java.util.Iterator;
013: import java.util.List;
014:
015: import org.jscience.mathematics.structure.GroupAdditive;
016: import org.jscience.mathematics.structure.GroupMultiplicative;
017:
018: import javolution.context.LocalContext;
019: import javolution.context.ObjectFactory;
020: import javolution.util.FastList;
021: import javolution.lang.Realtime;
022: import javolution.text.Text;
023: import 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: */
063: public 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(
141: "This function is not monovariate");
142: Variable<X> x = vars.get(0);
143: X prev = x.get();
144: LocalContext.enter();
145: try {
146: x.set(arg);
147: return evaluate();
148: } finally {
149: x.set(prev);
150: LocalContext.exit();
151: }
152: }
153:
154: /**
155: * Evaluates this function for the specified arguments values
156: * (convenience method). The evaluation is performed
157: * in a {@link javolution.context.LocalContext LocalContext} and
158: * can safely be called upon functions with {@link Variable.Global global
159: * variables}.
160: *
161: * @param args the variables values used for the evaluation.
162: * @return the evaluation of this function.
163: * @throws IllegalArgumentException
164: * if <code>args.length != getVariables().size())</code>
165: */
166: public final Y evaluate(X... args) {
167: List<Variable<X>> vars = getVariables();
168: if (vars.size() != args.length)
169: throw new IllegalArgumentException("Found " + args.length
170: + " arguments, but " + vars.size() + "required");
171: LocalContext.enter();
172: try {
173: return evaluate(args, vars, 0);
174: } finally {
175: LocalContext.exit();
176: }
177: }
178:
179: private final Y evaluate(X[] args, List<Variable<X>> vars, int i) {
180: if (i < args.length) {
181: Variable<X> var = vars.get(i);
182: X prev = var.get();
183: var.set(args[i]);
184: try {
185: return evaluate(args, vars, i + 1);
186: } finally {
187: var.set(prev); // Restores previous variable value.
188: }
189: } else {
190: return evaluate();
191: }
192: }
193:
194: /**
195: * Returns the composition of this function with the one specified.
196: *
197: * @param that the function for which the return value is passed as
198: * argument to this function.
199: * @return the function <code>(this o that)</code>
200: * @throws FunctionException if this function is not monovariate.
201: */
202: public <Z> Function<Z, Y> compose(Function<Z, X> that) {
203: if (getVariables().size() != 1)
204: throw new FunctionException(
205: "This function is not monovariate");
206: return Compose.newInstance(this , that);
207: }
208:
209: /**
210: * Returns the first derivative of this function with respect to
211: * the specified variable.
212: *
213: * @param v the variable for which the derivative is calculated.
214: * @return <code>d[this]/dv</code>
215: * @see <a href="http://mathworld.wolfram.com/Derivative.html">
216: * Derivative -- from MathWorld</a>
217: * @throws FunctionException if the derivative is undefined.
218: */
219: public Function<X, Y> differentiate(Variable<X> v) {
220: return Derivative.newInstance(this , v);
221: }
222:
223: /**
224: * Returns an integral of this function with respect to
225: * the specified variable.
226: *
227: * @param v the variable for which the integral is calculated.
228: * @return <code>S[this·dv]</code>
229: * @see <a href="http://mathworld.wolfram.com/Integral.html">
230: * Integral -- from MathWorld</a>
231: */
232: public Function<X, Y> integrate(Variable<X> v) {
233: return Integral.newInstance(this , v);
234: }
235:
236: /**
237: * Returns the sum of this function with the one specified.
238: *
239: * @param that the function to be added.
240: * @return <code>this + that</code>.
241: */
242: public Function<X, Y> plus(Function<X, Y> that) {
243: return Plus.newInstance(this , that);
244: }
245:
246: /**
247: * Returns the difference of this function with the one specified.
248: *
249: * @param that the function to be subtracted.
250: * @return <code>this - that</code>.
251: */
252: @SuppressWarnings("unchecked")
253: public Function<X, Y> minus(Function<X, Y> that) {
254: if (that instanceof GroupAdditive) {
255: Function thatOpposite = (Function) ((GroupAdditive) that)
256: .opposite();
257: return this .plus(thatOpposite);
258: }
259: return Minus.newInstance(this , that);
260: }
261:
262: /**
263: * Returns the product of this function with the one specified.
264: *
265: * @param that the function multiplier.
266: * @return <code>this · that</code>.
267: */
268: public Function<X, Y> times(Function<X, Y> that) {
269: return Times.newInstance(this , that);
270: }
271:
272: /**
273: * Returns the quotient of this function with the one specified.
274: * Evaluation of this function may raise an exception if the
275: * function result is not a {
276: *
277: * @param that the function divisor.
278: * @return <code>this / that</code>.
279: */
280: @SuppressWarnings("unchecked")
281: public Function<X, Y> divide(Function<X, Y> that) {
282: if (that instanceof GroupMultiplicative) {
283: Function thatInverse = (Function) ((GroupMultiplicative) that)
284: .inverse();
285: return this .times(thatInverse);
286: }
287: return Divide.newInstance(this , that);
288: }
289:
290: /**
291: * Returns this function raised at the specified exponent.
292: *
293: * @param n the exponent.
294: * @return <code>this<sup>n</sup></code>
295: * @throws IllegalArgumentException if <code>n <= 0</code>
296: */
297: public Function<X, Y> pow(int n) {
298: if (n <= 0)
299: throw new IllegalArgumentException("n: " + n
300: + " zero or negative values not allowed");
301: Function<X, Y> pow2 = this ;
302: Function<X, Y> result = null;
303: while (n >= 1) { // Iteration.
304: if ((n & 1) == 1) {
305: result = (result == null) ? pow2 : result.times(pow2);
306: }
307: pow2 = pow2.times(pow2);
308: n >>>= 1;
309: }
310: return result;
311: }
312:
313: /**
314: * Returns the textual representation of this real-time object
315: * (equivalent to <code>toString</code> except that the returned value
316: * can be allocated from the local context space).
317: *
318: * @return this object's textual representation.
319: */
320: public abstract Text toText();
321:
322: /**
323: * Returns the text representation of this function as a
324: * <code>java.lang.String</code>.
325: *
326: * @return <code>toText().toString()</code>
327: */
328: public final String toString() {
329: return toText().toString();
330: }
331:
332: // Merges the variable from the specified function into a single table.
333: @SuppressWarnings("unchecked")
334: static final List merge(List left, List right) {
335: if (left.containsAll(right))
336: return left;
337: if (right.containsAll(left))
338: return right;
339: FastList result = FastList.newInstance();
340: Iterator iLeft = left.iterator();
341: Iterator iRight = right.iterator();
342: Variable l = null;
343: Variable r = null;
344: while (true) {
345: if (!iLeft.hasNext()) {
346: while (iRight.hasNext()) {
347: result.add(iRight.next());
348: }
349: return result;
350: }
351: if (!iRight.hasNext()) {
352: while (iLeft.hasNext()) {
353: result.add(iLeft.next());
354: }
355: return result;
356: }
357: l = (l == null) ? (Variable) iLeft.next() : l;
358: r = (r == null) ? (Variable) iRight.next() : r;
359: if (l == r) {
360: result.add(l);
361: l = null;
362: r = null;
363: continue;
364: }
365: int comp = l.getSymbol().compareTo(r.getSymbol());
366: if (comp < 0) {
367: result.add(l);
368: l = null;
369: continue;
370: }
371: if (comp > 0) {
372: result.add(r);
373: r = null;
374: continue;
375: }
376: throw new FunctionException("Duplicate symbol "
377: + l.getSymbol());
378: }
379: }
380:
381: // Function composition (default implementation).
382: private static final class Compose extends Function {
383:
384: private static final ObjectFactory<Compose> FACTORY = new ObjectFactory<Compose>() {
385:
386: protected Compose create() {
387: return new Compose();
388: }
389:
390: protected void cleanup(Compose compose) {
391: compose._f = null;
392: compose._g = null;
393: }
394: };
395:
396: private Function _f;
397:
398: private Function _g;
399:
400: @SuppressWarnings("unchecked")
401: public static <X, Y> Function<X, Y> newInstance(Function f,
402: Function g) {
403: Compose compose = FACTORY.object();
404: compose._f = f;
405: compose._g = g;
406: return compose;
407: }
408:
409: @Override
410: public List getVariables() {
411: return _g.getVariables();
412: }
413:
414: @Override
415: @SuppressWarnings("unchecked")
416: public Object evaluate() {
417: return evaluate(_g.evaluate());
418: }
419:
420: @SuppressWarnings("unchecked")
421: public Function differentiate(Variable v) {
422: // Chain rule: http://en.wikipedia.org/wiki/Chain_rule
423: Function fd = _f.differentiate(v);
424: Function gd = _g.differentiate(v);
425: return fd.compose(_g).times(gd);
426: }
427:
428: public Text toText() {
429: return TextBuilder.newInstance().append('(').append(_f)
430: .append(')').append('o').append('(').append(_g)
431: .append(')').toText();
432: }
433:
434: @Override
435: public boolean equals(Object obj) {
436: if (!(obj instanceof Compose))
437: return false;
438: Compose that = (Compose) obj;
439: return this ._f.equals(that._f) && this ._g.equals(that._g);
440: }
441:
442: @Override
443: public int hashCode() {
444: return _f.hashCode() + _g.hashCode();
445: }
446:
447: private static final long serialVersionUID = 1L;
448:
449: }
450:
451: // Function derivative (default implementation).
452: private static final class Derivative extends Function {
453:
454: private static final ObjectFactory<Derivative> FACTORY = new ObjectFactory<Derivative>() {
455:
456: protected Derivative create() {
457: return new Derivative();
458: }
459:
460: protected void cleanup(Derivative derivative) {
461: derivative._f = null;
462: derivative._v = null;
463: }
464: };
465:
466: private Function _f;
467:
468: private Variable _v;
469:
470: @SuppressWarnings("unchecked")
471: public static <X, Y> Function<X, Y> newInstance(Function f,
472: Variable v) {
473: Derivative derivative = FACTORY.object();
474: derivative._f = f;
475: derivative._v = v;
476: return derivative;
477: }
478:
479: @Override
480: public List getVariables() {
481: return _f.getVariables();
482: }
483:
484: @Override
485: public Object evaluate() {
486: throw new FunctionException("Derivative of " + _f
487: + " undefined");
488: }
489:
490: public Text toText() {
491: return TextBuilder.newInstance().append("d[").append(_f)
492: .append("]/d").append(_v.getSymbol()).toText();
493: }
494:
495: @Override
496: public boolean equals(Object obj) {
497: if (!(obj instanceof Derivative))
498: return false;
499: Derivative that = (Derivative) obj;
500: return this ._f.equals(that._f) && this ._v.equals(that._v);
501: }
502:
503: @Override
504: public int hashCode() {
505: return _f.hashCode() + _v.hashCode();
506: }
507:
508: private static final long serialVersionUID = 1L;
509: }
510:
511: // Function integral (default implementation).
512: private static final class Integral extends Function {
513:
514: private static final ObjectFactory<Integral> FACTORY = new ObjectFactory<Integral>() {
515:
516: protected Integral create() {
517: return new Integral();
518: }
519:
520: protected void cleanup(Integral integral) {
521: integral._f = null;
522: integral._v = null;
523: }
524: };
525:
526: private Function _f;
527:
528: private Variable _v;
529:
530: @SuppressWarnings("unchecked")
531: public static <X, Y> Function<X, Y> newInstance(Function f,
532: Variable v) {
533: Integral integral = FACTORY.object();
534: integral._f = f;
535: integral._v = v;
536: return integral;
537: }
538:
539: @Override
540: public List getVariables() {
541: return _f.getVariables();
542: }
543:
544: @Override
545: public Object evaluate() {
546: throw new FunctionException("Integral of " + _f
547: + " undefined");
548: }
549:
550: public Text toText() {
551: return TextBuilder.newInstance().append("S[").append(_f)
552: .append("·d").append(_v.getSymbol()).append(']')
553: .toText();
554: }
555:
556: @Override
557: public boolean equals(Object obj) {
558: if (!(obj instanceof Integral))
559: return false;
560: Integral that = (Integral) obj;
561: return this ._f.equals(that._f) && this ._v.equals(that._v);
562: }
563:
564: @Override
565: public int hashCode() {
566: return _f.hashCode() + _v.hashCode();
567: }
568:
569: private static final long serialVersionUID = 1L;
570: }
571:
572: // Function addition (default implementation).
573: private static final class Plus extends Function {
574:
575: private static final ObjectFactory<Plus> FACTORY = new ObjectFactory<Plus>() {
576:
577: protected Plus create() {
578: return new Plus();
579: }
580:
581: protected void cleanup(Plus plus) {
582: plus._f = null;
583: plus._g = null;
584: }
585: };
586:
587: private Function _f, _g;
588:
589: @SuppressWarnings("unchecked")
590: public static <X, Y> Function<X, Y> newInstance(Function f,
591: Function g) {
592: Plus plus = FACTORY.object();
593: plus._f = f;
594: plus._g = g;
595: return plus;
596: }
597:
598: @Override
599: public List getVariables() {
600: return merge(_f.getVariables(), _g.getVariables());
601: }
602:
603: @SuppressWarnings("unchecked")
604: @Override
605: public Object evaluate() {
606: Object y2 = _g.evaluate();
607: Object y1 = _f.evaluate();
608: if (!(y1 instanceof GroupAdditive))
609: throw new FunctionException(y1.getClass()
610: + " is not an additive group");
611:
612: return ((GroupAdditive) y1).plus(y2);
613: }
614:
615: @SuppressWarnings("unchecked")
616: @Override
617: public Function differentiate(Variable v) {
618: return _f.differentiate(v).plus(_g.differentiate(v));
619: }
620:
621: @SuppressWarnings("unchecked")
622: @Override
623: public Function integrate(Variable v) {
624: return _f.integrate(v).plus(_g.integrate(v));
625: }
626:
627: public Text toText() {
628: return TextBuilder.newInstance().append('(').append(_f)
629: .append(")").append('+').append('(').append(_g)
630: .append(')').toText();
631: }
632:
633: @Override
634: public boolean equals(Object obj) {
635: if (!(obj instanceof Plus))
636: return false;
637: Plus that = (Plus) obj;
638: return this ._f.equals(that._f) && this ._g.equals(that._g);
639: }
640:
641: @Override
642: public int hashCode() {
643: return _f.hashCode() + _g.hashCode();
644: }
645:
646: private static final long serialVersionUID = 1L;
647: }
648:
649: // Function addition (default implementation).
650: private static final class Minus extends Function {
651:
652: private static final ObjectFactory<Minus> FACTORY = new ObjectFactory<Minus>() {
653:
654: protected Minus create() {
655: return new Minus();
656: }
657:
658: protected void cleanup(Minus minus) {
659: minus._f = null;
660: minus._g = null;
661: }
662: };
663:
664: private Function _f, _g;
665:
666: @SuppressWarnings("unchecked")
667: public static <X, Y> Function<X, Y> newInstance(Function f,
668: Function g) {
669: Minus minus = FACTORY.object();
670: minus._f = f;
671: minus._g = g;
672: return minus;
673: }
674:
675: @Override
676: public List getVariables() {
677: return merge(_f.getVariables(), _g.getVariables());
678: }
679:
680: @SuppressWarnings("unchecked")
681: @Override
682: public Object evaluate() {
683: Object y2 = _g.evaluate();
684: if (!(y2 instanceof GroupAdditive))
685: throw new FunctionException(y2.getClass()
686: + " is not an additive group");
687: y2 = ((GroupAdditive) y2).opposite();
688:
689: Object y1 = _f.evaluate();
690: if (!(y1 instanceof GroupAdditive))
691: throw new FunctionException(y1.getClass()
692: + " is not an additive group");
693:
694: return ((GroupAdditive) y1).plus(y2);
695: }
696:
697: @SuppressWarnings("unchecked")
698: @Override
699: public Function differentiate(Variable v) {
700: return _f.differentiate(v).minus(_g.differentiate(v));
701: }
702:
703: @SuppressWarnings("unchecked")
704: @Override
705: public Function integrate(Variable v) {
706: return _f.integrate(v).minus(_g.integrate(v));
707: }
708:
709: public Text toText() {
710: return TextBuilder.newInstance().append('(').append(_f)
711: .append(")").append('-').append('(').append(_g)
712: .append(')').toText();
713: }
714:
715: @Override
716: public boolean equals(Object obj) {
717: if (!(obj instanceof Minus))
718: return false;
719: Minus that = (Minus) obj;
720: return this ._f.equals(that._f) && this ._g.equals(that._g);
721: }
722:
723: @Override
724: public int hashCode() {
725: return _f.hashCode() + _g.hashCode();
726: }
727:
728: private static final long serialVersionUID = 1L;
729: }
730:
731: // Function multiplication (default implementation).
732: private static final class Times extends Function {
733:
734: private static final ObjectFactory<Times> FACTORY = new ObjectFactory<Times>() {
735:
736: protected Times create() {
737: return new Times();
738: }
739:
740: protected void cleanup(Times times) {
741: times._f = null;
742: times._g = null;
743: }
744: };
745:
746: private Function _f, _g;
747:
748: @SuppressWarnings("unchecked")
749: public static <X, Y> Function<X, Y> newInstance(Function f,
750: Function g) {
751: Times times = FACTORY.object();
752: times._f = f;
753: times._g = g;
754: return times;
755: }
756:
757: @Override
758: public List getVariables() {
759: return merge(_f.getVariables(), _g.getVariables());
760: }
761:
762: @SuppressWarnings("unchecked")
763: @Override
764: public Object evaluate() {
765: Object y2 = _g.evaluate();
766: Object y1 = _f.evaluate();
767: if (!(y1 instanceof GroupMultiplicative))
768: throw new FunctionException(y1.getClass()
769: + " is not a multiplicative group");
770:
771: return ((GroupMultiplicative) y1).times(y2);
772: }
773:
774: @SuppressWarnings("unchecked")
775: @Override
776: public Function differentiate(Variable v) {
777: // Product rule: http://en.wikipedia.org/wiki/Product_rule
778: // (support for non-commutative multiplications).
779: // r' = d(f·g) = f'g + fg'
780: Function fd = _f.differentiate(v);
781: Function gd = _g.differentiate(v);
782: return fd.times(_g).plus(_f.times(gd));
783: }
784:
785: public Text toText() {
786: return TextBuilder.newInstance().append('(').append(_f).append(")")
787: .append('·').append('(').append(_g).append(')').toText();
788: }
789:
790: @Override
791: public boolean equals(Object obj) {
792: if (!(obj instanceof Times))
793: return false;
794: Times that = (Times) obj;
795: return this ._f.equals(that._f) && this ._g.equals(that._g);
796: }
797:
798: @Override
799: public int hashCode() {
800: return _f.hashCode() + _g.hashCode();
801: }
802:
803: private static final long serialVersionUID = 1L;
804: }
805:
806: // Function multiplication (default implementation).
807: private static final class Divide extends Function {
808:
809: private static final ObjectFactory<Divide> FACTORY = new ObjectFactory<Divide>() {
810:
811: protected Divide create() {
812: return new Divide();
813: }
814:
815: protected void cleanup(Divide divide) {
816: divide._f = null;
817: divide._g = null;
818: }
819: };
820:
821: private Function _f, _g;
822:
823: @SuppressWarnings("unchecked")
824: public static <X, Y> Function<X, Y> newInstance(Function f,
825: Function g) {
826: Divide divide = FACTORY.object();
827: divide._f = f;
828: divide._g = g;
829: return divide;
830: }
831:
832: @Override
833: public List getVariables() {
834: return merge(_f.getVariables(), _g.getVariables());
835: }
836:
837: @SuppressWarnings("unchecked")
838: @Override
839: public Object evaluate() {
840: Object y2 = _g.evaluate();
841: if (!(y2 instanceof GroupMultiplicative))
842: throw new FunctionException(y2.getClass()
843: + " is not a multiplicative group");
844: y2 = ((GroupMultiplicative) y2).inverse();
845: Object y1 = _f.evaluate();
846: if (!(y1 instanceof GroupMultiplicative))
847: throw new FunctionException(y1.getClass()
848: + " is not a multiplicative group");
849:
850: return ((GroupMultiplicative) y1).times(y2);
851: }
852:
853: @SuppressWarnings("unchecked")
854: @Override
855: public Function differentiate(Variable v) {
856: // Quotient rule: http://en.wikipedia.org/wiki/Quotient_rule
857: // with support for non-commutative multiplications.
858: // r = f/g, rg = f, r'g + rg' = f' (produt rule)
859: // r' = (f' - rg')/g, r' = (f' - (f/g)g')/g
860: Function fd = _f.differentiate(v);
861: Function gd = _g.differentiate(v);
862: return fd.minus(_f.divide(_g).times(gd)).divide(_g);
863: }
864:
865: public Text toText() {
866: return TextBuilder.newInstance().append('(').append(_f)
867: .append(")").append('/').append('(').append(_g)
868: .append(')').toText();
869: }
870:
871: @Override
872: public boolean equals(Object obj) {
873: if (!(obj instanceof Divide))
874: return false;
875: Divide that = (Divide) obj;
876: return this ._f.equals(that._f) && this ._g.equals(that._g);
877: }
878:
879: @Override
880: public int hashCode() {
881: return _f.hashCode() + _g.hashCode();
882: }
883:
884: private static final long serialVersionUID = 1L;
885: }
886: }
|