CS 463 Project 1 Imperative/OOP Fractals The goal of a couple of our projects is to compare a simple project across different programming paradigms. This semester, we will calculate the Mandelbrot Set and Julia Set in both an imperative and functional language (Java and Haskell). Files Tester: Zoomer: Deadline: 11:59pm, Wednesday, February 20 th Remember, a project is a bit larger than a homework https://cs.gmu.edu/~marks/463/p/p1tests.java https://cs.gmu.edu/~marks/463/p/zoomer.java Turning it in Place all your files, including a README.txt file with any extra information, into a folder named after your username. Zip this folder and submit it to Blackboard. The Mandelbrot Set What is this? Well, it looks something like the following: Specifically, the dark regions are the Mandelbrot Set, and the zone that is colored various shades of red in our picture is outside of the set. The Mandelbrot Set is drawn across the complex plane real numbers on the horizontal axis, imaginary numbers on the vertical axis. Although we are zoomed in slightly here, the entire set fits inside [-2,2] and [-2i, 2i].
How do we calculate the Mandelbrot Set? Each individual point on the complex plane is either in the set or not. To find out if a particular point p is in the set, we let Z0=0, c=p, and repeatedly calculate the next Z using complex number operations: Zn+1 = (Zn) 2 + c If successive values of Z never get larger than 2, then the point c is in the set. If it escapes (grows too large and thus it can't get under 2 ever again), then it is not in the set. We must calculate "enough" iterations to approximate the Mandelbrot Set to sufficient accuracy. The more details you want to see on the boundary of the set, the more iterations you need. About 50 is sufficient for the image above, but if we were to zoom in we'd quickly want hundreds, thousands, or even millions of iterations per point to ensure you see the detail that exists at that level. Interesting Notes The Mandelbrot Set is connected all the black pixels are actually connected in the full set. By coloring points not in the set based on how many iterations it took for Z to escape, it makes for some very colorful images, and helps point out where the boundary of the set is. The length of the set's boundary is infinite. You can zoom in arbitrarily far at any point along the boundary and there will always be more details to see, as long as you're willing to wait around and precisely calculate each point! How do we calculate a Julia Set? The Julia Set is another fun group of fractals that we can define quite similarly to the Mandelbrot Set. We will again use the same function, only this time when we want to check if a point p is in the set or not, we let Z0=p, and c is some pre-determined constant. We then again iterate the same function (Zn+1 = (Zn) 2 + c) and see if it escapes, again by checking if the absolute value of Zn gets larger than 2. If we choose c=-0.62772+0.42193i, we get the image to the right. Task You are going to write a program in Java that calculates the Mandelbrot Set and the Julia Set, and stores the results in a file. You must have specific methods available in order for me to test your code, but also so that you can hook into a minimal GUI that will be provided for your viewing pleasure.
class Complex You must create your own version of complex numbers to use in this project, including the definitions below. It represents a Complex number, and also offers some binary operator methods (as static methods). You might visit the wiki page on complex numbers for a refresher of these definitions. Fields: double r, i; Methods: public Complex (double r, double i){ } public static Complex add(complex a, Complex b){ } public static Complex sub(complex a, Complex b){ } public static Complex mul(complex a, Complex b){ } public static double abs(complex c){ } @Override String tostring() { /*your choice*/ } public Complex copy(){ } abstract class Fractal You will create a single class that relates both Mandelbrot and Julia classes. This will store all the information related to the structure of the viewing region, iterations, and so on, but won't encode the actual function that gets iterated. Fields: Complex low, high; int nrows, ncols; int maxiters; int[][]escapevals; Complex c; // lower-left and upper-right coordinates // pixel counting how many pixels in each direction // how many iterations to consider for set inclusion // cached answers for each point's iterations to escape // what is the c value of the iteration function? (boring for Mandelbrot) Methods: public abstract int escapecount(complex p); Given one point p, how many iterations can you follow, up to maxiters, before it escapes? This means all points in the set will return maxiters. public int[][] escapes() { } Calculate escape counts for each point indicated by current instance variables; return this array of escape counts. First row is the HIGHEST imaginary values row, from low real values to high values as you go through the first row of this array. Starting with range low=-2-2i, high=+2+2i, this means you should have answer[0][0] @ (-2+2i), answer[0][ncols-1] @ (+2+2i), answer[nrows-1][0] @ (-2-2i), and answer[nrows-1]ncols-1] @ (+2-2i). Draw yourself a picture so you understand the layout. public void write(string filename) { } Given a file name, calculate all escape counts as needed, and create a file containing these lines. (See example below): o nrows ncols maxiters o lowrealval highrealval lowimaginaryval highimaginaryval o realc imaginaryc (parts of the constant c) o <a blank line> o each row from escapevals as a line, with its values separated by whitespace (you should pad all items to the same minimal spacing width as shown below) public void zoom(double factor){ } Given a factor, stay centered on the same spot but scale it by factor so that each dimension sees 1/factor of its previous range. For instance, zooming in by factor=2, we should see half the distance of the previous real range and half the distance of the previous imaginary range. This doesn't mean we're seeing half the original image, by the way. public void updatedimensions(complex low, Complex high) { } Straight-up reset low and high, and recalculate other stale state (escape counts) as necessary. @Override public String tostring() { /*your choice*/ } Make it pretty. might help with write.
class Mandelbrot public Mandelbrot(Complex low, Complex high, int nrows, int ncols, int maxiters){ } Set all fields (note: not all are parameters). public int escapecount(complex p){ } implement this abstract method inherited from the parent class so that it correctly uses the given point to calculate how many iterations (up to maxiters) before it escapes. @Override public String tostring(){ /*your choice*/ } Add any more methods as needed. public static void main(string[] args){ }. Accept eight command line arguments: doubles for the four dimensions (lowr, highr, lowi, highi), followed by three integers (nrows, ncols, maxiters). Lastly, accept the filename. Create the Mandelbrot object, calculate all escape counts, and write to the file. Pay close attention to the arguments order! See an example below. Usage will be like this: demo$ java Mandelbrot -2 2-2 2 15 15 40 tinym.txt And then tiny.txt would look like this: demo$ cat tinym.txt 15 15 40-2.0 2.0-2.0 2.0 0.0 0.0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 1 2 2 2 3 3 1 1 1 1 1 0 0 0 1 2 2 3 3 11 15 3 2 1 1 1 1 0 0 2 2 3 4 33 40 40 40 2 1 1 1 1 0 0 3 4 29 9 40 40 40 40 3 2 1 1 1 0 40 40 40 40 40 40 40 40 14 3 2 1 1 1 1 0 3 4 29 9 40 40 40 40 3 2 1 1 1 0 0 2 2 3 4 33 40 40 40 2 1 1 1 1 0 0 1 2 2 3 3 11 15 3 2 1 1 1 1 0 0 0 1 2 2 2 3 3 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 Definitely not tiny.. The file first echoes the number of rows, number of columns, and the maximum number of iterations checked. Then we see the dimensions (lowr, highr, lowi, highi). C is always 0+0i for Mandelbrot, but the file format will be used for Julia sets too so we need this line always. Notice that some spots are at the total number of iterations (40 here); those are assumed to be in the set. Also, note that it uses three columns for each number: a space, maybe a second space for numbers <10, and then the number; this just makes it look nice. If maxiters were a three-column number, we'd need four columns for each number. We normally would want much larger parameters say, 400x400, with at least 50 iterations. If you are careful to give the same spacing for each escape value, and you make your font ridiculously tiny, you can get a neat ASCII art representation of the set, as shown in the blue screencap of a terminal above. No GUI necessary! Ah, cheap programming thrills. When performing your calculations, make sure that the leftmost column starts at -2, and the rightmost column has a real component of +2. The rest should all be distributed evenly. Watch out for fenceposting issues! Similarly so for the imaginary components, make sure they stretch all the way from -2i to +2i.
class Julia public Julia (Complex low, Complex high, int nrows, int ncols, int maxiters, Complex c){ } Same as Mandelbrot set all fields, including escapevals. public int escapecount(complex p){ } Same as with class Mandelbrot, only implement the correct function for Julia Sets. @Override public String tostring(){ /*your choice*/ } Add any more methods as needed. public static void main(string[] args){ }. Accept ten command line arguments: doubles for the four dimensions (lowr, highr, lowi, highi), followed by three integers (nrows, ncols, maxiters). Two extra ones here that Mandelbrot didn't have, the real and imaginary components of c. Lastly, accept the filename. Create the Julia object, calculate all escape counts, and write to the file. It operates the same as the Mandelbrot example. Usage will be like this: demo$ java Julia -2 2-2 2 15 15 40 -.62772.42193 tinyj.txt And then tiny.txt would look like this: demo$ cat tinyj.txt 15 15 40-2.0 2.0-2.0 2.0-0.62772 0.42193 0 0 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 1 2 3 4 2 1 1 0 0 0 0 0 0 1 3 5 7 40 40 3 2 1 1 0 0 0 0 0 6 40 40 40 40 12 6 5 4 1 1 0 0 0 0 1 4 8 40 40 40 40 40 8 4 1 0 0 0 0 1 1 4 5 6 12 40 40 40 40 6 0 0 0 0 0 1 1 2 3 40 40 7 5 3 1 0 0 0 0 0 0 1 1 2 4 3 2 1 1 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 Visualizing it: Using a GUI I'm not generally interested in GUIs too much personally, but this is a great chance to do so. Provided will be a Java file (Zoomer.java) that will directly access your classes' methods, and it will try to color code them nicely. Currently, you'd have to directly modify a few constants at the top (IMG_WIDTH, Complex c, etc). You'll have to add a few methods to fully use it, but you can click-drag to zoom in, and change the number of iterations. Fun! Mostly, this is a simple way to check if you're getting the right format for everything it's not part of the testing or grading. You're free to make your own GUI backend if you'd like you can select the colors probably a lot better than I did. If you do so, I'd love to see it! Usage: demo$ java Zoomer
Grading Grading is based on correctness, and performed via test cases. We will try to award credit, or subtract points, based on the following weightings. Of course, when things go wrong, it's often in interesting and unexpected ways. We'll try to be fair. Complex 15% Fractal escapes 15% write 10% zoom 10% updatedimensions 5% Mandelbrot constructor 10% escapecount 10% main 5% Julia constructor 5% escapecount 10% main 5% Lastly: comment your code well. The more interesting or difficult it is, the more comments it should have. No block of code should be without comments, though repetitive blocks may be commented mostly at the beginning. Low/uncommented code may lose points; you should be able to comment your code by a deadline by this point in your college career. turn in your work correctly, and on time according to our syllabus' description of our late work policy. don't import anything you didn't write for this assignment (other than for writing to files). This is especially important when defining your Complex class; I'm looking for your own definition. (You may look up the mathematics of complex numbers, e.g. on Wikipedia, but you may not look up code for complex numbers in any language).