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

Second commit

parent d09235fc
Branches
Tags
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