Skip to content
Snippets Groups Projects
Commit d4d7fa9f authored by Luigi Santocanale's avatar Luigi Santocanale
Browse files

Second commit

parent d09235fc
Branches
No related tags found
No related merge requests found
Makefile 0 → 100644
# Cible qui pour compiler
compile:
# Cible qui explique comment executer
exec:
# Demarre automatiquement une demonstration de votre programme
# Il faut que cette demo soit convaincante
demo:
# Executer automatiquent les test
# On s'attend (d'habitude) que pour claque classe MaClasse il y ait une
# classe TestMaClasse qui vorifie le bon comportment de chaque methode de la classe
# sur au moins une entrée
test:
# Pour la cible suivante, on vous laisse faire
clean:
File added
resources/randomBFS.png

721 KiB

resources/randomKruskal.png

4.91 KiB

resources/randomWilson.png

794 KiB

public class Arc {
Edge support;
boolean reversed;
public Arc(Edge e, boolean reversed) {
this.support = e;
this.reversed = reversed;
}
public int getSource() {
return (reversed ? support.getDest() : support.getSource());
}
public int getDest() {
return (reversed ? support.getSource() : support.getDest());
}
}
public class Complete {
Graph graph;
public Complete(int order) {
this.graph = new Graph(order);
for(int i = 0; i < order; i++)
for (int j = i+1; j < order; j++)
graph.addEdge(new Edge(i,j,0));
}
}
public class Edge implements Comparable<Edge> {
protected int source;
protected int dest;
double weight;
public Edge(int source, int dest, double weight) {
this.source = source;
this.dest = dest;
this.weight = weight;
}
public int compareTo(Edge e) {
if (this.weight == e.weight) return 0;
if (this.weight < e.weight) return -1;
return 1;
}
public int oppositeExtremity(int vertex) {
return (dest == vertex ? source : dest);
}
public int getSource() {
return this.source;
}
public int getDest() {
return this.dest;
}
}
import java.util.ArrayList;
import java.util.Random;
public class ErdosRenyi {
private final static Random gen = new Random();
Graph graph;
private int order;
private double edgeProbability;
private boolean isConnected() {
if (graph == null) return false;
ArrayList<Arc> tree = BreadthFirstSearch.generateTree(graph, 0);
return tree.size() == order - 1;
}
private void genGraph() {
graph = new Graph(order);
for (int i = 0; i < order; i++)
for (int j = i+1; j < order; j++) {
if (gen.nextDouble() < edgeProbability)
graph.addEdge(new Edge(i,j,0));
}
}
public ErdosRenyi(int order, float expectedAverageDegree) {
this.edgeProbability = Math.max(1.5, expectedAverageDegree) / (order-1);
this.order = order;
while (!isConnected()) genGraph();
}
}
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class Graph implements Iterable<Edge>{
// classe de graphe non orientés permettant de manipuler
// en même temps des arcs (orientés)
// pour pouvoir stocker un arbre couvrant, en plus du graphe
int order;
int edgeCardinality;
ArrayList<LinkedList<Edge>> adjacency;
ArrayList<LinkedList<Arc>> inAdjacency;
ArrayList<LinkedList<Arc>> outAdjacency;
public boolean isVertex(int index) {
// à remplir
}
public <T> ArrayList<LinkedList<T>> makeList(int size) {
ArrayList<LinkedList<T>> res = new ArrayList<>(size);
for(int i = 0; i <= size; i++) {
res.add(null);
}
return res;
}
public Graph(int upperBound) {
// à remplir
}
public void addVertex(int indexVertex) {
// à remplir
}
public void ensureVertex(int indexVertex) {
// à remplir
}
public void addArc(Arc arc) {
// à remplir
}
public void addEdge(Edge e) {
// à remplir
}
}
import java.util.BitSet;
public class Grid {
int width;
int height;
int maxVertex;
Graph graph;
public int abscissaOfVertex(int vertex) {
return vertex % width;
}
public int ordinateOfVertex(int vertex) {
return vertex / width;
}
private int vertexOfCoordinate(int abscissa, int ordinate) {
return ordinate * width + abscissa;
}
public Grid(int width, int height) {
this.width = width;
this.height = height;
maxVertex = width * height - 1;
graph = new Graph(maxVertex);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
if (i < width - 1)
graph.addEdge(new Edge(
vertexOfCoordinate(i,j),
vertexOfCoordinate(i+1,j),
0.0
));
if (j < height - 1)
graph.addEdge(new Edge(
vertexOfCoordinate(i,j),
vertexOfCoordinate(i,j+1),
0.0
));
}
}
}
public boolean isHorizontal(Edge e) {
return Math.abs(e.source - e.dest) == 1;
}
public boolean isVertical(Edge e) {
return Math.abs(e.source - e.dest) == width;
}
private void drawLine(int h, BitSet right) {
for (int i = 0; i < width - 1; i++) {
System.out.print("o");
if (right.get(vertexOfCoordinate(i,h))) System.out.print("--");
else System.out.print(" ");
}
System.out.println("o");
}
private void drawInterline(int h, BitSet up) {
for (int i = 0; i < width; i++) {
if (up.get(vertexOfCoordinate(i,h))) System.out.print("|");
else System.out.print(" ");
if (i < width-1) System.out.print(" ");
}
System.out.println();
}
public void drawSubgrid(Iterable<Edge> edges) {
BitSet up = new BitSet(maxVertex);
BitSet right = new BitSet(maxVertex);
for (Edge e : edges) {
// System.out.println(e.fromVertex + " -- " + e.toVertex);
if (isHorizontal(e))
right.set(Math.min(e.source,e.dest));
if (isVertical(e))
up.set(Math.min(e.source,e.dest));
}
for (int j = 0; j < height; j++) {
drawLine(j,right);
if (j < height - 1) drawInterline(j,up);
}
}
}
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class Labyrinth extends JPanel {
private static final long serialVersionUID = 2192694920147985L;
int halfSide = 5;
int vertexMargin = 1;
int corridorMargin = 2;
int corridorLength = 2 * halfSide;
int side;
int vertexRadius;
int vertexWidth;
int corridorWidth;
int corridorStartShift;
int colorGradientCycleLength = 150; // > 0
int brightnessSlope= 3; // 0 <= x <= 100
int minBrightness = 40; // 0 <= x <= 100
Color backgroundColor = Color.black;
BufferedImage img;
private void recomputeDefaultValues() {
side = 2 * halfSide + 1;
vertexWidth = side - 2 * vertexMargin;
corridorWidth = side - 2 * corridorMargin;
corridorStartShift = side / 2 + 1;
vertexRadius = halfSide - vertexMargin;
}
Grid grid;
RootedTree tree;
ArrayList<Edge> edges;
public void setStyleBright() {
colorGradientCycleLength = 150;
brightnessSlope = 0;
minBrightness = 100;
backgroundColor = Color.black;
}
public void setStyleInverted() {
colorGradientCycleLength = 150;
brightnessSlope = 2;
minBrightness = 10;
backgroundColor = Color.gray;
}
public void setStyleBalanced() {
colorGradientCycleLength = 150;
brightnessSlope = 3;
minBrightness = 40;
backgroundColor = Color.black;
}
public void setShapeBigNodes() {
halfSide = 10;
vertexMargin = 1;
corridorMargin = 5;
recomputeDefaultValues();
}
public void setShapeSmoothSmallNodes() {
halfSide = 5;
vertexMargin = 1;
corridorMargin = 1;
recomputeDefaultValues();
}
public void setShapeSmallAndFull() {
halfSide = 5;
vertexMargin = 0;
corridorMargin = 0;
recomputeDefaultValues();
}
public Labyrinth(Grid g, RootedTree tree) {
this.grid = g;
this.tree = tree;
edges = new ArrayList<>();
recomputeDefaultValues();
setPreferredSize(new Dimension(side * grid.width,side*grid.height));
img = new BufferedImage(
side * grid.width,
side * grid.height,
BufferedImage.TYPE_3BYTE_BGR
);
}
public void addEdge(Edge e) {
edges.add(e);
}
private Color getVertexColor(int vertex) {
if (tree == null) return Color.white;
int depth = tree.getDepth(vertex);
int height = tree.getHeight(vertex) + 1;
float hue = (float)
(depth % colorGradientCycleLength) / colorGradientCycleLength;
float saturation = (float) 0.7;
float brightness = (float)
Math.min(100, brightnessSlope * height + minBrightness) / 100;
Color col = Color.getHSBColor(hue, saturation, brightness);
return col;
}
private void drawVerticalEdge(Graphics2D g, Edge e) {
int source = Math.min(e.source, e.dest);
int dest = Math.max(e.source,e.dest);
int xMin = side * grid.abscissaOfVertex(source) + corridorMargin;
int yMin = side * grid.ordinateOfVertex(source) + corridorStartShift;
Rectangle rect = new Rectangle(xMin,yMin,corridorWidth, 2*halfSide);
GradientPaint gradient;
gradient = new GradientPaint(
xMin, yMin + vertexRadius - 1, getVertexColor(source),
xMin, yMin + 2*halfSide - vertexRadius, getVertexColor(dest)
);
g.setPaint(gradient);
g.fill(rect);
}
private void drawHorizontalEdge(Graphics2D g, Edge e) {
int source = Math.min(e.source, e.dest);
int dest = Math.max(e.source,e.dest);
int xMin = side * grid.abscissaOfVertex(source) + corridorStartShift;
int yMin = side * grid.ordinateOfVertex(source) + corridorMargin;
Rectangle rect = new Rectangle(xMin, yMin, 2*halfSide, corridorWidth);
GradientPaint gradient = new GradientPaint(
xMin + vertexRadius - 1, yMin, getVertexColor(source),
xMin + 2*halfSide - vertexRadius, yMin, getVertexColor(dest)
);
g.setPaint(gradient);
g.fill(rect);
}
private void drawVertex(Graphics2D g, int vertex) {
int xMin = side * grid.abscissaOfVertex(vertex) + vertexMargin;
int yMin = side * grid.ordinateOfVertex(vertex) + vertexMargin;
Shape ell = new Ellipse2D.Float(xMin,yMin,vertexWidth,vertexWidth);
g.setPaint(getVertexColor(vertex));
g.fill(ell);
}
private void drawRoot(Graphics2D g, int vertex) {
int i = grid.abscissaOfVertex(vertex);
int j = grid.ordinateOfVertex(vertex);
g.setColor(Color.white);
g.fillRect(side * i, side * j, side, side);
}
private void drawBackground(Graphics2D g) {
super.setBackground(backgroundColor);
super.paintComponent(g);
}
public void drawLabyrinth() {
Graphics2D g = img.createGraphics();
RenderingHints rh = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
);
g.setRenderingHints(rh);
drawBackground(g);
g.setColor(Color.white);
for (Edge e : edges) {
if (grid.isHorizontal(e)) drawHorizontalEdge(g,e);
else drawVerticalEdge(g,e);
}
for (int i = 0; i < grid.graph.order; i++) {
drawVertex(g,i);
}
if (tree != null) drawRoot(g,tree.getRoot());
g.dispose();
repaint();
}
@Override
public void paintComponent(Graphics graphics) {
Graphics2D g = (Graphics2D) graphics;
g.drawImage(img,0,0,null);
}
public void saveImage(String path) throws IOException {
ImageIO.write((RenderedImage) img,"PNG", new File(path));
}
}
import java.util.ArrayList;
import java.util.Collections;
public class Lollipop {
Graph graph;
public Lollipop(int order) {
graph = new Graph(order);
ArrayList<Integer> permutation = new ArrayList<>(order);
for (int i = 0; i < order; i++)
permutation.add(i);
Collections.shuffle(permutation);
int t = order / 3;
for (int i = 0; i < t; i++)
graph.addEdge(new Edge(permutation.get(i),permutation.get(i+1),0));
for (int i = t; i < order; i++)
for (int j = i+1; j < order; j++)
graph.addEdge(new Edge(permutation.get(i),
permutation.get(j),
0
)
);
}
}
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class MainStub {
@SuppressWarnings("unused")
private final static Random gen = new Random();
public static ArrayList<Edge> genTree(Graph graph) {
ArrayList<Edge> randomTree;
// TOOO : modifier l'algorithme utiliser ici.
// Non-random BFS
ArrayList<Arc> randomArcTree =
BreadthFirstSearch.generateTree(graph,0);
randomTree = new ArrayList<>();
for (Arc a : randomArcTree) randomTree.add(a.support);
return randomTree;
}
public static void main(String argv[]) throws InterruptedException {
Grid grid = null;
grid = new Grid(1920/11,1080/11);
Graph graph = grid.graph;
// Graph graph = new Complete(400).graph;
// Graph graph = new ErdosRenyi(1_000, 100).graph;
// Graph graph = new Lollipop(1_000).graph;
int nbrOfSamples = 10;
int diameterSum = 0;
double eccentricitySum = 0;
long wienerSum = 0;
int degreesSum[] = {0, 0, 0, 0, 0};
int degrees[];
ArrayList<Edge> randomTree = null;
RootedTree rooted = null;
long startingTime = System.nanoTime();
for (int i = 0; i < nbrOfSamples; i++) {
randomTree= genTree(graph);
rooted = new RootedTree(randomTree,0);
// rooted.printStats();
diameterSum = diameterSum + rooted.getDiameter();
eccentricitySum = eccentricitySum + rooted.getAverageEccentricity();
wienerSum = wienerSum + rooted.getWienerIndex();
degrees = rooted.getDegreeDistribution(4);
for (int j = 1; j < 5; j++) {
degreesSum[j] = degreesSum[j] + degrees[j];
}
}
long delay = System.nanoTime() - startingTime;
System.out.println("On " + nbrOfSamples + " samples:");
System.out.println("Average eccentricity: "
+ (eccentricitySum / nbrOfSamples));
System.out.println("Average wiener index: "
+ (wienerSum / nbrOfSamples));
System.out.println("Average diameter: "
+ (diameterSum / nbrOfSamples));
System.out.println("Average number of leaves: "
+ (degreesSum[1] / nbrOfSamples));
System.out.println("Average number of degree 2 vertices: "
+ (degreesSum[2] / nbrOfSamples));
System.out.println("Average computation time: "
+ delay / (nbrOfSamples * 1_000_000) + "ms");
if (grid != null) showGrid(grid,rooted,randomTree);
}
private static void showGrid(
Grid grid,
RootedTree rooted,
ArrayList<Edge> randomTree
) throws InterruptedException {
JFrame window = new JFrame("solution");
final Labyrinth laby = new Labyrinth(grid, rooted);
laby.setStyleBalanced();
// laby.setShapeBigNodes();
// laby.setShapeSmallAndFull();
laby.setShapeSmoothSmallNodes();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.getContentPane().add(laby);
window.pack();
window.setLocationRelativeTo(null);
for (final Edge e : randomTree) {
laby.addEdge(e);
}
laby.drawLabyrinth();
window.setVisible(true);
// Pour générer un fichier image.
// try {
// laby.saveImage("resources/random.png");
// } catch (IOException e1) {
// e1.printStackTrace();
// }
}
}
import java.util.ArrayList;
import java.util.BitSet;
import java.util.LinkedList;
import java.util.Stack;
public class Parcours {
Graph graph;
Stack<Arc> frontier;
BitSet reached;
ArrayList<Arc> predecessor;
private void etendsFrontiere(int sommet) {
for (Arc a : graph.outNeighbours(sommet))
frontier.add(a);
}
private void explore(Arc a) {
if (reached.get(a.getDest())) return;
reached.set(a.getDest());
etendsFrontiere(a.getDest());
predecessor.set(a.getDest(), a);
}
private void parcours(int source) {
reached.set(source);
etendsFrontiere(source);
while (!frontier.isEmpty())
explore(frontier.pop());
}
private Parcours(Graph graph) {
this.graph = graph;
this.frontier = new Stack<>();
this.reached = new BitSet(graph.order);
this.predecessor = new ArrayList<>(graph.order);
for (int i = 0; i < graph.order; i++) {
predecessor.add(null);
}
}
public static ArrayList<Arc> algo(Graph graph, int source) {
Parcours p = new Parcours(graph);
p.parcours(source);
return p.predecessor;
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Queue;
public class RootedTree {
private int getHeight(Node n) {
return (n == null ? -1 : n.height);
}
private int getSize(Node n) {
return (n == null ? -1 : n.size);
}
private class Node {
int vertex;
ArrayList<Node> sons;
int height;
int size;
int depth;
public Node(int vertex) {
this.vertex = vertex;
this.sons = new ArrayList<>();
this.height = 0;
}
public void setHeight() {
int maxHeight = -1;
for (Node son : this.sons)
maxHeight = Math.max(maxHeight, son.height);
this.height = maxHeight + 1;
}
private void setSize() {
size = 1;
for (Node son : this.sons) size = size + son.size;
}
private void setSonsDepth() {
for (Node son : this.sons) son.depth = this.depth + 1;
}
private Node maxSizeSon() {
Node maxSon = null;
for (Node son : sons) {
if (son.size > getSize(maxSon)) maxSon = son;
}
return maxSon;
}
private Node maxHeightSon() {
Node maxSon = null;
for (Node son : sons) {
if (son.height > getHeight(maxSon)) maxSon = son;
}
return maxSon;
}
private int secondMaxHeight() {
int maxHeight = -1;
int secondMaxHeight = -1;
for (Node son : sons) {
if (son.height > secondMaxHeight) {
secondMaxHeight = Math.min(maxHeight, son.height);
maxHeight = Math.max(maxHeight, son.height);
}
}
return secondMaxHeight;
}
private void print() {
System.out.print("Node " + this.vertex + ", sons: ");
for (Node son : this.sons) {
System.out.print(son.vertex + " ");
}
System.out.println("(height: " + this.height
+ ", size: " + this.size
+ ", 2nd height: " + this.secondMaxHeight()
+ ", depth: " + this.depth
+ ")");
}
}
// to write recursive algorithms without recursion
ArrayList<Node> inverseBfsOrder;
ArrayList<Node> bfsOrder;
Node nodes[];
Node root;
int order;
// Tree initialization
public void computeAllHeights() {
for(Node n : inverseBfsOrder) n.setHeight();
}
public void computeAllSizes() {
for (Node n : inverseBfsOrder) n.setSize();
}
public void computeAllDepths() {
root.depth = 0;
for (Node n : bfsOrder) n.setSonsDepth();
}
// Tree invariants
// sum of distances between all pairs of vertices.
public long getWienerIndex() {
long count = 0;
for (Node n : bfsOrder) {
if (n == root) continue;
count = count + n.size * (order - n.size);
}
return count;
}
public int[] getDegreeDistribution(int maxDegree) {
int maxIndex = Math.min(maxDegree,order-1);
int[] degrees = new int[1+maxIndex];
for(int i = 0; i <= maxIndex; i++) degrees[i] = 0;
int degree;
for (Node n : bfsOrder) {
degree = n.sons.size() + (n == root ? 0 : 1);
if (degree <= maxIndex)
degrees[degree]++;
}
return degrees;
}
public int getRadius() {
return root.height;
}
public int getDiameter() {
return root.height + root.secondMaxHeight() + 1;
}
private Node getCentroidNode() {
Node centroid = root;
while (centroid.maxSizeSon().size * 2 > order)
centroid = centroid.maxSizeSon();
return centroid;
}
public int getDistanceFromCenterToCentroid() {
return getCentroidNode().depth;
}
public double getAverageEccentricity() {
int sumEccentricity = 0;
for (Node n : bfsOrder)
sumEccentricity = sumEccentricity + n.depth;
return (double) sumEccentricity / (double) order;
}
// Node accessors
public int getRoot() { return root.vertex; }
public int getHeight(int vertex) {
return nodes[vertex].height;
}
public int getDepth(int vertex) {
return nodes[vertex].depth;
}
public int getSubtreeSize(int vertex) {
return nodes[vertex].size;
}
public int getCentroid() {
return getCentroidNode().vertex;
}
// printers
public void printStats() {
System.out.println("Order: " + order);
System.out.println("Diameter: " + getDiameter());
System.out.println("Radius: " + getRadius());
System.out.println("Wiener index: " + getWienerIndex());
System.out.println("Center to centroid: "
+ getDistanceFromCenterToCentroid());
System.out.println("Average eccentricity: "
+ getAverageEccentricity());
}
public void printNode(int vertex) {
nodes[vertex].print();
}
public void printTree() {
for (Node n : bfsOrder) n.print();
}
// Below to end: building the tree from list of arcs.
// We want the center of the tree as root.
// 1) createTree: Gets a tree encoded in the Node structure.
// This is done by using bfs algorithm on the graph of edges.
// From the bfs list of arcs, creates each node and attach it to father
// Stores each node in an array indexed by vertices.
// 2) Computes the height of every node, in inverse bfs order.
// 3) rerootTree: Moves root toward center.
// the two highest sons must have almost the same height.
// it detects if it is balanced,
// and if not moves the root to the highest son (swapRootWith)
// 4) resetBfsOrdering : recomputes bfs and inverse bfs order.
// this time, a bfs on the node structure is enough
// 5) Computes height, size and depth of every node.
private void resetBfsOrdering() {
Queue<Node> stack = new LinkedList<Node>();
stack.offer(root);
bfsOrder.clear();
inverseBfsOrder.clear();
Node current;
while (!stack.isEmpty()) {
current = stack.poll();
for (Node son : current.sons) stack.offer(son);
bfsOrder.add(current);
inverseBfsOrder.add(current);
}
Collections.reverse(inverseBfsOrder);
}
private void swapRootWith(Node son) {
root.sons.remove(son);
root.setHeight();
son.height = Math.max(root.height + 1, son.height);
son.sons.add(root);
root = son;
}
private boolean isUnbalanced() {
return root.height > root.secondMaxHeight() + 2;
}
private void rerootTree() {
computeAllHeights();
while (isUnbalanced())
swapRootWith(root.maxHeightSon());
resetBfsOrdering();
}
private void createNode(Node nodes[], Arc arc) {
int son = arc.getDest();
int father = arc.getSource();
nodes[son] = new Node(son);
nodes[father].sons.add(nodes[son]);
}
private void createTree(int root, ArrayList<Arc> sortedArcs) {
this.bfsOrder = new ArrayList<>(order);
this.inverseBfsOrder = new ArrayList<>(order);
nodes = new Node[order];
nodes[root] = new Node(root);
this.bfsOrder.add(nodes[root]);
for (Arc arc : sortedArcs) {
createNode(nodes,arc);
this.bfsOrder.add(nodes[arc.getDest()]);
}
inverseBfsOrder.addAll(bfsOrder);
Collections.reverse(inverseBfsOrder);
this.root = nodes[root];
}
public RootedTree(ArrayList<Edge> edges, int root) {
this.order = edges.size() + 1;
Graph graph = new Graph(order);
for (Edge e : edges) graph.addEdge(e);
createTree(root, BreadthFirstSearch.generateTree(graph, root));
rerootTree();
computeAllHeights();
computeAllSizes();
computeAllDepths();
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment