Due Friday, March 8, 2019, 11:59 PM

This project is concerned with representing mathematical expressions in software so they can be manipulated in various ways and evaluated.

We define the abstraction called `Function`

that
represents any calculation that can be treated as the definition
of a mathematical function of one variable. Your job is first to
express `Function`

as an abstract Java class (or
interface) and then to build concrete implementors of the
`Function`

abstraction and for each one implement `Function`

's
operations:

`evaluate`

: Given a double floating point value of x, compute the value of the function.`toString`

: Return a human-readable expression of the function as a Java String.`Function`

s using an infix operator with two or more operands must include parentheses.`derivative`

: Return the`Function`

that is the (first) derivative of the function with respect to x.`integral`

: Compute the (double) value of the definite integral of the function with respect to x over a given interval. The interval is expressed by two double arguments. For all but the simplest functions the integral has to be computed numerically using the trapezoid rule, so the number of trapezoids (i.e. the granularity of the calculation) is also given in case it is needed.`isConstant`

: Answer whether or not this function is constant (including if it is a combination of other constants).

The set of classes in the `Function`

hierarchy form a
classic Composite
design pattern. Some functions are primitive; they have no smaller
parts. The simple constant and the expression *x* are the
most common examples of primitive equations. Most other functions
are composites, meaning that they are composed of other "smaller"
functions. For example, *2x* is a product composite
containing the primitives *2*, a constant, and *x*, a
simple variable. Observe the following figure.

*sin(x)* is a transcendental function that is actually a
composite but containing only one subordinate. *sin(2x)* is
an instance of the sine composite with a multiplication composite
inside it, which in turn contains two primitives.

*2x·sin(x)* would at the top level be a product containing
three functions:

Now let's look at what the operations listed above do to some of these functions.

*2x*:

- Calling
`evaluate`

with argument 7.5 would yield the double 15.0. - Calling
`toString`

would yield`( 2 * x )`

. - Calling
`derivative`

would yield a`Constant`

object representing the value 2.0. - Calling
`integral`

from 1.0 to 5.0 would hopefully yield something close to the value of*x*at 5.0 minus the value of^{2}*x*at 1.0, or 24.0. However, since there is no universal closed form for integrating products, it has to be calculated by numerical means. The larger the 3rd argument is, the closer to 24.0 the answer should be.^{2} `isConstant`

would yield false.

*sin(2x)*:

- Calling
`evaluate`

with argument 7.5 would yield the double 0.65028784016. - Calling
`toString`

would yield`sin( ( 2 * x ) )`

. - Calling
`derivative`

would yield a`Product`

object representing the function*2·cos(2x)* - Calling
`integral`

from 1.0 to 5.0 would yield something close to the value of*-cos(2x)/2*at 5.0 minus the value of*-cos(2x)/2*at 1.0, or 0.21146234626. - Calling
`isConstant`

would yield false.

The third example *2x·sin(x)* would of course be even more
complex. However, it is important to remember that each function
only deals with its immediate descendants. The full answer is
computed by using recursion.

The derivative is always calculable in closed form. Here are some things to remember.

- The derivative of a sum is the sum of the derivatives.
- The derivative of a product
*yz*is*y*times the derivative of*z*plus*z*times the derivative of*y*. (You must generalize this to a product of more than two factors. Think recursively!) - The derivative of
*f(g(x))*with respect to*x*is the derivative of*f(g(x))*with respect to*g(x)*times the derivative of*g(x)*with respect to*x.*(This is the chain rule.) - The integral of a sum is the sum of the integrals.
- Functions containing products and trigonometric functions cannot be integrated to a closed form. (Remember, you cannot assume the argument of sine or cosine is simply x.) It is for these cases that you must approximate the integral with the trapezoid rule. This occurs in multiple functions, but you should figure out how to implement it only once!

`isConstant()`

can be defined recursively, if you
look at functions as forming trees, as they did in the figures
above. A `Function`

object is constant if:

- It is an instance of
`Constant`

(base case), or - all of its "child"
`Function`

objects are constant.

In the discussion below the term "constant" refers to any object
that answers true to `isConstant`

().

- If several constants are provided to the
`Sum`

or`Product`

constructor, they should be combined into a single`Constant`

instance. Example:`2.0 * sin( x ) * 3.0`

should be`sin( x ) * 6.0`

. - An empty (size 0)
`Sum`

or`Product`

should represent 0.0 or 1.0, respectively. - If in the end the
`Sum`

or`Product`

contains a`Constant`

equal to 0 or 1, respectively, it must be eliminated altogether from the sequence of terms stored unless it is the only one left.

Clearly one can do many other things to reduce the size of the
`Sum`

and `Product`

objects' string representations.
*Do not do any other simplifications besides the ones explained
above for Constants.*

You will notice that some class's constructors, such as `Sum`

's,
accept a variable
number of arguments. Here is how you allow it. If you define a method
in this way

public void foo( Thing... all ) { … }

It means that you have a choice on how to call the method. First, you can pass a primitive array of the expected type:

Thing[] things = … ; foo( things );

And in fact, inside the method, the parameter (`all`

) will
be a reference to that array.

However the caller can choose to list elements explicitly.

Thing t1 = …; Thing t2 = …; Thing t3 = …; foo( t1, t2, t3 );

They will still be packaged up into the `all`

array inside
the method. So for the Sum class you might write

public Sum( Function... terms ) { … }

You are free to implement your `Function` class as either
an interface or an abstract class. The advantage of using an
abstract class is that you can remove some of the redundancy
you'll encounter with an interface.

We are providing three test programs here. The expected output is in comments at the bottom of the program. You should make sure your output matches exactly.

Keep in mind these are not complete. Your own tests in `FunctionTest`
should be much more rigorous.

Although this project only has one due date, you can use the requirements in Part One to make sure you are not too far behind. Set a goal to get this part finished two weeks before the due date. Note that some points are awarded based only on the Part One instructions.

Write Java code to declare Function as described in section 2, but without the integral method, then write the following implementing classes:

`Constant`

-- The constructor takes the value as its argument.`Variable`

-- This constructor takes no argument, since the only variable allowed is x. There should only be one instance of`Variable`

. Therefore, the constructor is private and there is a public final static instance of`Variable`

within the Variable class. The instance's name should be`X`

.`Sum`

-- The constructor takes an argument list of functions to be added together.

Example: the function *2x + 7* could be
constructed as follows: ```
new Sum( Variable.X, Variable.X,
new Constant( 7 ) )
```

NOTE: The above function will print out as `(x + x + 7)`

- do not attempt to make special code to have it print as `2x + 7`

as you could have many different complicated Sums and should not
make special cases for every case!

Important: The `Sum`

constructor is declared as
follows: `public Sum( Function... terms ) { ... }`

This way, it can accept either an array of `Function`

s
or a sequence of separate `Function`

arguments (as in
the *2x+7* example above). In either case, the number of
Function terms is not fixed. Inside the method, `terms`

is
treated as if it were declared as `Function[]`

. This rule also
applies to the `Product`

constructor.

Finally, you must also write a test program **FunctionTest1**
that thoroughly exercises the above code.

Add the `integral`

method to the `Function`

interface/class. Override the method
only in the classes where the integral is bound to have a closed
form, i.e., `Constant`

, `Variable`

, and
`Sum`

. Next, write the following
additional descendants of `Function`

:

`Product`

-- constructor takes an argument list of functions to be multiplied together.`Product`

should treat`Constant`

s like`Sum`

does, but there are two differences. First, if all the`Constant`

factors multiply to 1, then it can be eliminated unless it's the only one left. Second, if they all multiply to 0, then the`Product`

should be made up of a single`Constant`

factor 0.`Sine`

-- constructor takes a function to which the sine function is to be applied.`Cosine`

-- constructor takes a function to which the cosine function is to be applied.

new Sum( new Product( Variable.X, Variable.X ), new Cosine( new Product( new Constant(2), Variable.X ) ), new Constant( 7 ) )

Again, note that this should be printed as
`( ( x * x ) + cos( ( 2 * x ) ) + 7.0 )`

.

Finally, you must extend your test program so that it thoroughly
exercises all of your code.
Call the new one **FunctionTest2**.

When you are done your IntelliJ IDEA™ project source directory should show these contents.

To submit, do the following.

- Go to your project directory.
- Zip up your
**src/**folder and name the file**project1.zip**.

(Make sure the zip file does not contain the**.idea**directory or any**.iml**file.) - Upload your zip file to the MyCourses dropbox for Project 1.

Don't forget to verify that your submission went through and that the zip file's contents are correct.

Your grade is based on the following aspects of your work.

- Part One: 30%
- Conforming design - 10%
- Functional correctness - 15%
- Part 1 Test program completeness - 5%

- Part Two: 70%
- Conforming design - 5%
- Functional correctness - 40%
- Sufficient commits to repository - 5%
- Conforming source code style - 10%
- Part 2 Test program completeness - 10%*

* The Part 2 Test must test all functionality, not just that added since Part 1.