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 <= 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}