Skip to content

Commit

Permalink
REFACTOR: New Power() stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
itays123 committed Oct 28, 2023
1 parent 42072e7 commit 5ab4666
Show file tree
Hide file tree
Showing 12 changed files with 356 additions and 139 deletions.
4 changes: 2 additions & 2 deletions App.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import function.Function;
import function.FunctionVector;
import function.Identity;
import function.elementary.ExponentialFunction;
import function.elementary.PowerFunction;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
Expand All @@ -20,7 +20,7 @@ public void start(Stage stage) throws Exception {
StackPane layout = new StackPane(canvas);
layout.setPadding(new Insets(20));

Function f = new ExponentialFunction().compose(FunctionVector.scale(PowerFunction.of(2), -1));
Function f = new ExponentialFunction().compose(FunctionVector.scale(new Identity().squared(), -1));
canvas.addFunction(f, -5, 5, Color.DARKCYAN, 1);

stage.setTitle(f.toString());
Expand Down
4 changes: 2 additions & 2 deletions function/Constant.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package function;

import function.elementary.PowerFunction;
import function.arithmetics.Power;

/**
* Represents a function f(x)=1
Expand Down Expand Up @@ -49,7 +49,7 @@ public Function times(Function other) {

@Override
public Function div(Function other) {
return PowerFunction.of(-1).compose(other);
return Power.inverse(other);
}

@Override
Expand Down
36 changes: 33 additions & 3 deletions function/Function.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package function;

import function.arithmetics.Compose;
import function.arithmetics.Power;
import function.arithmetics.Product;
import function.arithmetics.Quotient;
import function.elementary.PowerFunction;

/**
* Represents a function in java
Expand Down Expand Up @@ -82,8 +82,11 @@ public Function minus(Function other) {
public Function times(Function other) {
if (other instanceof Constant)
return this;
if (other instanceof FunctionVector || other instanceof Product || other instanceof Quotient)
if (other instanceof FunctionVector || other instanceof Product || other instanceof Quotient
|| (!(this instanceof Power) && other instanceof Power))
return other.times(this);
if (this.equals(other))
return this.squared();
return new Product(this, other);
};

Expand All @@ -104,6 +107,10 @@ public Function div(Function other) {
Quotient quo = (Quotient) other;
return this.times(quo.getRight()).div(quo.getLeft());
}
if (this.equals(other))
return Constant.of(1);
if (other instanceof Power && this.equals(((Power) other).getLeft())) // apply rule a / a^n = a^(1-n)
return new Power(this, Constant.of(1)).div(other);
return new Quotient(this, other);
};

Expand All @@ -116,7 +123,7 @@ public Function div(Function other) {
* @return the composed function
*/
public Function compose(Function inner) {
if (inner.equals(PowerFunction.IDENTITY))
if (inner instanceof Identity)
return this;
if (inner instanceof Constant)
return Constant.of(evaluate(inner.evaluate(0))); // will just give us the value at 1
Expand All @@ -127,6 +134,29 @@ public Function compose(Function inner) {
return new Compose(this, inner);
};

/**
* Returns a function that is equivalent to this function, to the power of
* another function.
*
* @param exponent the function that will be the exponent of this function
*/
public Function pow(Function exponent) {
if (exponent.equals(Constant.of(1)))
return this;
if (FunctionVector.getScalar(exponent) == 0)
return Constant.of(1);
return new Power(this, exponent);
}

/**
* Returns this function squared
*
* @return the square of this function
*/
public Function squared() {
return this.pow(Constant.of(2));
}

/**
* Checks if the function is equal to another
*
Expand Down
16 changes: 13 additions & 3 deletions function/FunctionVector.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,21 @@ public static double getScalar(Function func) {
if (!(func instanceof FunctionVector))
return 1;
FunctionVector vec = (FunctionVector) func;
if (vec.getSize() != 1)
if (vec.getSize() > 1)
return 1;
for (Scale<Function> term : vec.terms) { // remember there is only one
return term.getScalar();
}
return 1; // should not get here;
return 0;
}

public static Function getScaledFunc(Function func) {
if (getScalar(func) == 1)
throw new IllegalArgumentException("Cannot de-scale a vector with scalar 1");
for (Scale<Function> term : ((FunctionVector) func).terms) { // remember there is only one
return term.getVector();
}
return new FunctionVector(); // should not get here
}

/**
Expand Down Expand Up @@ -159,7 +168,8 @@ public Function times(Function other) {

@Override
public Function div(Function other) {
// TODO: Implement function division
if (getScalar(this) == 0)
return new FunctionVector();

return super.div(other);
}
Expand Down
33 changes: 33 additions & 0 deletions function/Identity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package function;

/**
* Represents the identity function f(x)=x
*/
public class Identity extends Function {

@Override
public double evaluate(double x) throws ArithmeticException {
return x;
}

@Override
public Function derive() {
return Constant.of(1);
}

@Override
public String substitute(String x) {
return x;
}

@Override
public boolean equals(Object obj) {
return obj instanceof Identity;
}

@Override
public Function compose(Function inner) {
return inner;
}

}
100 changes: 100 additions & 0 deletions function/arithmetics/Power.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package function.arithmetics;

import function.Constant;
import function.Function;
import function.elementary.LogarithmicFunction;

/**
* Represents the function left^right
*/
public class Power extends FunctionArithmetic {

public static Function inverse(Function other) {
return other.pow(Constant.of(-1));
}

public Power(Function left, Function right) {
super(left, right);
}

@Override
public double evaluate(double x) throws ArithmeticException {
double leftVal = left.evaluate(x);
double rightVal = right.evaluate(x);
if (leftVal == 0 && rightVal < 0)
throw new ArithmeticException("Can't divide by 0");
return Math.pow(leftVal, rightVal);
}

@Override
public Function derive() {
// f^g is equivalent to e^(ln(f)*g)
// deriving ln(f)*g gives us (f'g/f + ln(f)*g')
// Therefore, the derivative would be (f'g/f + ln(f)*g') * e^(ln(f) * g), which
// is equivalent to (f'g/f + ln(f)*g') * (f^g)
Function innerDerivative = left.derive().times(right).div(left)
.plus(right.derive().times(new LogarithmicFunction().compose(left)));
return innerDerivative.times(this);
}

@Override
public String substitute(String x) {
return left.substitute(x, true) + "^" + right.substitute(x, true);
}

@Override
public Function times(Function other) {
if (other instanceof Power) {
Power pow = (Power) other;

// apply rule #1: a^n * a^m = a^(n+m)
if (left.equals(pow.left))
return left.pow(right.plus(pow.right));

// don't apply rule #2: a^n * b^n = (ab)^n, unless simpler:
if (right.equals(pow.right) && !(left.times(pow.left) instanceof Product))
return left.times(pow.left).pow(right);

}

// apply rule #1 again:
if (left.equals(other))
return times(new Power(other, Constant.of(1)));

return super.times(other);
}

@Override
public Function div(Function other) {

if (other instanceof Power) {
Power pow = (Power) other;

// apply rule #1: a^n / a^m = a^(n-m)
if (left.equals(pow.left))
return left.pow(right.minus(pow.right));

// don't apply rule #2: a^n / b^n = (a/b)^n, unless simpler:
if (right.equals(pow.right) && !(left.div(pow.left) instanceof Quotient))
return left.div(pow.left).pow(right);

}

// apply rule #1 again:
if (left.equals(other))
return div(new Power(other, Constant.of(1)));

return super.div(other);
}

@Override
public Function compose(Function inner) {
return left.compose(inner).pow(right.compose(inner));
}

@Override
public Function pow(Function exponent) {
return left.pow(right.times(exponent)); // apply rule (a^b)^c = a^(bc)
}

}
22 changes: 22 additions & 0 deletions function/arithmetics/Product.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,28 @@ public Function times(Function other) {
return super.times(other);
}

@Override
public Function div(Function other) {
Function prod;

// try resolving to the left
prod = left.div(other);
if (!(prod instanceof Quotient))
return new Product(prod, right);

// try resolving to the right
prod = right.div(other);
if (!(prod instanceof Quotient))
return new Product(left, prod);

return super.div(other);
}

@Override
public Function pow(Function exponent) {
return left.pow(exponent).times(right.pow(exponent));
}

@Override
public boolean equals(Object other) {
if (!(other instanceof Product))
Expand Down
8 changes: 6 additions & 2 deletions function/arithmetics/Quotient.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package function.arithmetics;

import function.Function;
import function.elementary.PowerFunction;

/**
* Represents a ratio of two functions
Expand All @@ -21,7 +20,7 @@ public double evaluate(double x) throws ArithmeticException {
public Function derive() {
// based on formula [f/g]'=(f'g-fg')/g^2
Function numerator = left.derive().times(right).minus(left.times(right.derive()));
Function denominator = PowerFunction.of(2).compose(right);
Function denominator = right.squared();
return numerator.div(denominator);
}

Expand All @@ -39,4 +38,9 @@ public Function div(Function other) {
return left.div(right.times(other));
}

@Override
public Function pow(Function exponent) {
return left.pow(exponent).div(right.pow(exponent));
}

}
44 changes: 9 additions & 35 deletions function/elementary/ExponentialFunction.java
Original file line number Diff line number Diff line change
@@ -1,47 +1,21 @@
package function.elementary;

import function.Function;
import function.FunctionVector;
import function.Constant;
import function.Identity;
import function.arithmetics.Power;

public class ExponentialFunction extends Function {

private double base;
/**
* Represents the function e to the power of f(x)
*/
public class ExponentialFunction extends Power {

public ExponentialFunction() {
this(Math.E);
}

public ExponentialFunction(double base) {
if (base < 0)
throw new IllegalArgumentException("Can only pick a positive base");
if (base == 1 || base == 0)
throw new IllegalArgumentException("Pick a constant of " + base + " instead");
this.base = base;
}

@Override
public double evaluate(double x) throws ArithmeticException {
return Math.pow(base, x);
}

@Override
public Function derive() {
return FunctionVector.scale(new ExponentialFunction(base), Math.log(base));
super(Constant.of(Math.E), new Identity());
}

@Override
public String substitute(String x) {
String baseStr = String.valueOf(base);
if (base == Math.E)
baseStr = "e";
return baseStr + "^" + x;
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof ExponentialFunction))
return false;
return base == ((ExponentialFunction) obj).base;
return "e^" + x;
}

}
Loading

0 comments on commit 5ab4666

Please sign in to comment.