A program I wrote while at Summer Ventures of Science and Math to generate the bifurcation diagram. You can zoom in on portions of the diagram to see the self-similarity.
read morePlotter.java
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
@SuppressWarnings("serial")
public class Plotter extends JFrame implements MouseListener,
MouseMotionListener, ActionListener {
int dotSize = 1;
int xPixDragged;
int yPixDragged;
int prevMouseXCoord;
int prevMouseYCoord;
boolean dragging;
int counter = 0;
double xMin;
double xMax;
double yMin;
double yMax;
public JPanel resetPanel = new JPanel(); //Adds an instance of the JPanel class: created below
public JButton resetButton = new JButton("Reset view");
public PlotPanel plotPanel = new PlotPanel();
int oldMouseX;
int oldMouseY;
boolean axesVisible;
int numOfPoints;
double[] xCoords;
double[] yCoords;
boolean hasPoints = false;
public Plotter() { // this is the default constructor for Plotter -- it creates an instance of Plotter
setTitle("Point Plotter"); //This sets to the default object, that object is Plotter in this case
setSize(10000, 10000); //Sets the bounds of the window
add(resetPanel, BorderLayout.SOUTH);//Introduces the JPanel to this method
resetPanel.add(resetButton);//Adds the created JButton
resetButton.addActionListener(this);//Adds an action listener to the button
add(plotPanel);//This refers to the default object
plotPanel.addMouseListener(this);
plotPanel.addMouseMotionListener(this);
setLocationRelativeTo(null);
}
public void setCoordinateBounds(double xmin, double xmax, double ymin,
double ymax) {
xMin = xmin;
xMax = xmax;
yMin = ymin;
yMax = ymax;
repaint();
}
public void setAxesVisible(boolean vis) {
axesVisible = vis;
repaint();
}
public void setPointSet(double[] xc, double[] yc) {
xCoords = xc;
yCoords = yc;
numOfPoints = xc.length;
hasPoints = true;
repaint();
}
public int getYPixCoord(double yCoord) {
return (int) (getHeight() - ((yCoord - yMin) * getHeight() / (yMax - yMin)));
}
public int getXPixCoord(double xCoord) {
return (int) ((xCoord - xMin) * getHeight() / (xMax - xMin));
}
public double getXCoord(int xPixCoord) {
return xMin + (xPixCoord) * (xMax - xMin) / getWidth();
}
public double getYCoord(int yPixCoord) {
return yMax - (yPixCoord) * (yMax - yMin) / getHeight();
}
@Override
public void actionPerformed(ActionEvent event) {
setCoordinateBounds(1, 5, 0, 1);
}
@Override
public void mouseDragged(MouseEvent event) {
counter++;
int mouseX = event.getX();
int mouseY = event.getY();
double xInc = getXCoord(mouseX) - getXCoord(oldMouseX);
double yInc = getYCoord(mouseY) - getYCoord(oldMouseY);
// System.out.println("'real' coord of the mouse was:("+getXCoord(mouseX)+","+getYCoord(mouseY)+")");
xMax -= xInc;
xMin -= xInc;
yMin -= yInc;
yMax -= yInc;
if (counter == 2) {
// System.out.println("Updating the display");
counter = 0;
repaint();
}
oldMouseX = mouseX;
oldMouseY = mouseY;
}
@Override
public void mouseMoved(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
oldMouseX = mouseX;
oldMouseY = mouseY;
}
public class PlotPanel extends JPanel { //Creates a class
public void paintComponent(Graphics g) {
if (hasPoints) {
if (axesVisible) {
g.drawLine(0, getYPixCoord(0), getWidth(), getYPixCoord(0));
g.drawLine(getXPixCoord(0), 0, getXPixCoord(0), getHeight());
}
for (int i = 0; i < xCoords.length; i++) {
int pixX = getXPixCoord(xCoords[i]);
int pixY = getYPixCoord(yCoords[i]);
if (pixX >= 0 && pixY >= 0 && pixX < getWidth()
&& pixY < getHeight()) {
g.fillRect(pixX, pixY, dotSize, dotSize);
}
}
}
}
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
System.out.println("Mouse event was :" + e.getModifiers());
if (e.getModifiers() == 4) {
zoomIn(getXCoord(e.getX()), getYCoord(e.getY()));
}
}
public void zoomIn(double x, double y) {
double wid = xMax - xMin;
double hei = yMax - yMin;
setCoordinateBounds(x - wid / 4, x + wid / 4, y - hei / 4, y + hei / 4);
}
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
pointCreater.java
import java.util.Scanner;
import javax.swing.JSlider;
public class pointCreater {
/**
* I have an idea, what about taking the derivative of the entire
* Bifurcation Diagram? Never mind. Possible reason for "The Beast," it's
* likely to do with the precision of the "observable" condition, when
* altered, the regular bifurcation diagram returns :(.
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scan = new Scanner(System.in);
StringBuilder result = new StringBuilder();
System.out.println("Enter a starting x value");
double xStart = scan.nextDouble();
int pointCount = 0;
double y = 0;
int f = 0;
double y2 = 0;
double y4 = 0;
double y6 = 0;
double y8 = 0;
int r = 0;
double y1 = 0;
int arrayBounds = 3000000;
double[] xCoords = new double[arrayBounds];
double[] yCoords = new double[arrayBounds];
boolean convergenceForK = false;
boolean chaos = false;
double x;
Plotter plot = new Plotter();
plot.setVisible(true);
plot.setCoordinateBounds(1, 5, 0, 1);
for (double k = 1.01; k < 5; k += .001) { // Varies the K constant in
// the equation
// System.out.println("K=" + k);
y1 = 567444;
y2 = 456;
y4 = 4235;
x = xStart;
for (int a = 0; a < 100; a++) { // Iterates the function many times
y = k * (x - (x * x));
// System.out.println("Y=" + y);
convergenceForK = false;
chaos = false; // Resets the chaos value in case it was
// previously true
if (Math.abs(y - y1) < .000001 || Math.abs(y - y2) < .000001
|| Math.abs(y - y4) < .000001
|| Math.abs(y - y6) < .000001
|| Math.abs(y - y8) < .000001) {
// Checks to see if
// consecutive values of
// outputs are close,
// also values skipping
// an output, skipping 3
// outputs, etc.
convergenceForK = true;// if any pattern is found it jumps
// jumps to plotting the points
a = 300; // it stops the iteration
}
if (Math.abs(y - y1) > .00000001
&& Math.abs(y - y2) > .00000001
&& Math.abs(y - y4) > .00000001
&& Math.abs(y - y6) > .00000001
&& Math.abs(y - y8) > .00000001) {
chaos = true; // If no pattern is found, it jumps
}
y1 = y;
if (a % 2 == 0) {
y2 = y;
}
if (a % 4 == 0) {
y4 = y;
}
if (a % 6 == 0) {
y6 = y;
}
if (a % 8 == 0) {
y8 = y;
}
x = y;
}
r = 0;
if (convergenceForK) {
while (r < 1) {
y = k * (x - (x * x));
xCoords[pointCount] = k; // Now for each of the numerous
// outputs
yCoords[pointCount] = y;
// System.out.println("X coord:" + k + " Y coord:" +
// y);
pointCount++;
x = y;
r++;
}
}
if (chaos) {
f += 1;
while (r < 500) {
y = k * (x - (x * x));
xCoords[pointCount] = k;
yCoords[pointCount] = y;
// System.out.println("X coord:" + k + " Y coord:" +
// y);
pointCount++;
x = y;
r++;
}
}
}
plot.setPointSet(xCoords, yCoords);
System.out.println("F=" + f);
}
}
varyingKValues.java
import java.util.Scanner;
import java.applet.Applet;
import java.awt.*;
import java.util.*;
public class varyingKValues {
/** Experiment further between 3.21 & 3.4
* Starting K Value of .13
* y=k(x-x^2)
* It appears as though period doubling occurs to a very minor degree at most, if not all k values. As k grows, so does the
* magnitude of the period doubling. Paradoxically, as each iteration continues, the period doubling (subsides/magnifies)?.
* Examples: k=2.5
* Period Doubling noted here:
* First Bifurcation: 2.85-2.89; Noticeable at 3.03.
* Strange split, not very definite, starts around 3.21. Visible at 3.4.
* Second Bifurcation: 3.4735;
* Could interdependence be going on? It appears as though these equations flow nicely, perhaps the y value of the previous
* system determines both the x value of the next as well as the K value.
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scan = new Scanner(System.in);
StringBuilder result = new StringBuilder();
System.out.println("Enter a starting x value");
double x = scan.nextDouble();
double y = 0;
for (int i = 50; i > 0; i--) {
y = 1.1*(x-(x*x));
System.out.print(x);
System.out.print(" "+y+" "+"23");
System.out.println();
x = y;
}
}}