Skip to content

CPL2011/CPL1

Repository files navigation

FINAL
_____
As mentioned in a previous commit edges can be successfully added directly to the graph now.
Apart from this I also wanted to explicitly code in the directed/undirected aspects, but it seems as if this can't be done as cleanly as I hoped.

The following code successfully displays 'arrowheads' where appropriate, what should probably be added are overrided methods to add and remove nodes in UndirVisualizable...
In practice this struck me as ugly though, so I'm not sure if I should go on or just abort...

Either way, the project should be coming to a close...if you want to I'll commit this, but perhaps we might leave it as it is?
If you want to you can commit this as well, it's valid, working code (some access modifiers in Visualizable might have to be modified though)

Keep in mind that I wont have much time to do work on thursday (probably just enough to document The graph package classes).

package graph

trait DirVisualizable extends Visualizable {

  override def visualizeEdges(updateEdge : Edge => Any) = {
    ubigraphClient.setEdgeStyleAttribute(0, "arrow", "true")
    super.visualizeEdges(updateEdge)
  }
  
  /**
   * Adds unidirectional edges between nodes in the graph that are not yet connected,
   * with a given probability.
   */
  def addEdges(probability: Double) = {
    val destinations = nodes.values.toList
    nodes.values.foreach(source =>
      destinations.foreach(destination =>
        if(source != destination && !source.getNeighbours.contains(destination) && Math.random < probability)
          source.addNeighbour(destination)
      )
    )
  }
}




package graph
import scala.collection.immutable.HashMap

trait UndirVisualizable extends Visualizable {

  override def visualizeEdges(updateEdge : Edge => Any) = {
    ubigraphClient.setEdgeStyleAttribute(0, "arrow", "false")
    unvisualizeEdgesToBeRemoved
    var edges = new HashMap[(Int,Int),Edge]
    nodes.values.foreach(e => e.originatingEdges.values.foreach(edge => if(!edges.contains(edge.source.label,edge.destination.label) && !edges.contains(edge.destination.label,edge.source.label)) edges += (((edge.source.label, edge.destination.label),edge))))
    edges.values.foreach(e => if (visualizedEdges.contains(e)) updateEdge(e) else {
      if (ubigraphClient.newEdge(cantorPairing(e.source.label, e.destination.label), e.source.label, e.destination.label) == 0) {
        visualizedEdges += e
        updateEdge(e)
      } else System.err.println("Error: The edge (" + e.source.label + "," + e.destination.label + ") has already been visualized. The internal logic should prevent this from occurring")
    }) 

  }
  
  /**
   * Adds bidirectional edges between nodes in the graph that are not yet connected,
   * with a given probability.
   */
  def addEdges(probability: Double) = {
    var destinations = nodes.values.toList.tail
    nodes.values.foreach(source => {
      if (!destinations.isEmpty) {
        destinations.foreach(destination =>  
          if (!source.getNeighbours.contains(destination) && Math.random < probability) {
            source.addNeighbour(destination)
            destination.addNeighbour(source)
          }
        )
        destinations = destinations.tail 
      }
    })
  }	
}




TODO's
____________

SCALA: 
- class Graph, Node, Edge: functionality = (add Node, remove Node, add Edge, remove Edge, get Neighbours, 
(undirected edges are represented using two directed edges), get all Nodes, 
traversing the graph: Breadth-first, Depth-first)
- Node, Edge and Graph will use a 'visualization' trait to provide the Ubigraph functionality
- visualization needs some init , refresh functionality
if you call visualization multiple times. You get duplicates in ubigraph. But there should be a way to add and visualize new Nodes/Edges during simulation. I created some temporary methods in the example.fluspread but this is clearly not enough.
- Simulation Engine: ...?
- I think the library must give the user some help(errors) to setup his custom Node. Some suggestions:

* Create RoundGraph trait and add the entire graph to the engine. Trait will provide one of the functions below

RoundGraph.getRoundClients():List[RoundClient]
constructor RoundEngine(RoundGraph)

or
RoundGraph.doRound(timestamp:Int,duration:Int)
this for each engineType of course.

* Make Node abstract and create abstract method for doRound doTurn...
In this case user must create all abstract functions but he desides wich he implements.

Graph has no list of Edges...
But he needs them in the visualize method,
so we hack the liberary to get a list of edges.
What was the reason that Graph Shouldn't have a list of Edges?
----------> At some point I got the request that nodes should maintain a list of their edges, 
----------> and that the graph should thus no longer maintain such a list. Which is why the current version 
----------> does not have such a list

XML: 
- loading and storing...db4o? GraphML GEXP? get feedback

INSTALL UBIGRAPH:
http://ubietylab.net/ubigraph/content/Docs/index.html#languagebindings (Java)
(install apache-xmlrpc-3.1.3 and UbiGraph-alpa-0.2.4-Linux32-Debian-4)


BUGS
_____________
* There is no way I can define myEdge extends Edge and add use this edge to connect two Nodes with each other.
-----------> Correct, I've been thinking about a way of doing this (and all other extension-related things) I've 
-----------> considered generics (though it seems to work it's not very elegant, seeing how graphs only store nodes
-----------> and nodes actually store edges), setters and overridden methods but none of those methods seem very clean.
-----------> Open to suggestions.
-----------> All remaining problems seem to originate from this. I think generics is the way to go, altough
-----------> I'm not quite certain about what methods to drop and keep (for example edges should then no longer be
-----------> created inside the graph-related classes,...) Either way, if you have a good idea feel free to just 
-----------> go and implement it.

* With the new version of the graph I still need to overide the graph as I need the ubigraphClient variable to for the update function to work...
-----------> In the current version you can call setRemoteUbigraphServerHost(string: n) on a class extending trait Visualisable
-----------> in order to connect the client to a server with the given location as string. I don't seem able to run it, 
-----------> I probably just can't, so I'd like to hear from you if it works as expected.

Graph.visualize(UpdateVisualization) -> I find this kind of weard...
where to visualize? How should I use this function..? 
What if I want to change the initial visualization??
-----------> Check out simulation/Test.scala to get an idea of how the function should be used
-----------> If the current method has limitations feelf free to list them. And I'll see what I can do


Suggestion::::
Perhaps provide dummy methods that the user can override. The methods will have basic functionality so by using super this functionality can be extended by the user. Method calls will be automaticaly by the framework and a parameter ubigraph will be delivered.

Pseudocode framework
- Node.initVisualization(ubigraphClient) {addNodeToUbigraph}
- Node.visualize(ubigraphClient) {
	//Perhaps to some automatic updateing to the node.
	//Ex: If Node.color is added to library updates of colors can 	  be done here
}
------------> Shouldn't this behaviour be already present? 'initvisualization' essentially just provides you with a 
------------> visualization of the - at that moment - current state of the graph, which is what the visualize() method
------------> currently does. The ubigraphClient can be retrieved by calling .ubigraphClient on the graph extending the 
------------> Visualizable trait (don't forget to set the remote server if necessary) and then any functionality
------------> you might place in an 'overridden function' can just be given as a parameter (= higher order function)

Pseudocode myNode extends Node
override def myNode.initVisualization(ubi){
	//super.initVisualization(ubi)
	set some extra parameters on the new object.
	Perhaps the size of the structure.
}

override def myNode.visualize(ubi){
	super.visualize(ubi)
	//Add some custom visualization
}
------------> this pseudocode doesn't really make sence, you're trying to override a visualization-related method
------------> in something that just extends Node. I thought we opted to completely seperate visualization
------------> aspects from the underlying graph
//----------> Ah I think I understand, it's the problem with accessing the vars of your extended Node thing?
//----------> this could also be solved by relying on generics? Either way, I'm not really certain I understand 
//----------> the reasoning entirely...feel free to make changes where appropriate.
///You understand it verry well. Visualization should not be in Node but in some trait. Lets try to find another way then using generics. :p


- I need to update ubigraphClient for my server to work all right. So if you make ubigraphclient a val I can't visualize. Perhaps make two constructors of VisualizableGraph. One with the serverString and one Witout...
------------> Should no longer be an issue

IN PROGRESS
_____________
- the db4o storage still does not work properly and I probably do not have the time today/tomorrow to fix it... 
The problem is that db4o does not store the references that are stored in the graph object. I tried the config
method, but it did not work.

- Simulation Engine ready for inspection


DONE
_____________
- Most basic functionality has been provided but things might still have to be refactored into different classes/traits 
(for 'traversing' check the ideas below, for visualizing the graph, a more robust strategy might be neat)
- trait 'infectable'
- Because of the problems with the object databases that I had(I'm sure that I probably made some stupid
mistakes), I have implemented a load/store mechanism based on xml. It is a bit more code that with db4o,
but at least it works:) Just do "graph.save(path)" to save it, and to load from a file use "graph2.loadGraph(path)"
- Fixed db4o store



IDEAS
_____________
I have made a simple scala.swing gui that can be used to pass arguments (such as the ubigraph server) to our
tests. As of now I only implemented some input fields, but they dont do anything. I would like to get some 
feedback on this, what elements should I add to the gui? Or am I wasting my time with this?:p
-------> It's not a huge priority, but if the other work has been done it's an excellent thing to spend time on.
-------> I don't know how the xml stuff actually works... if there's the ability to explicitly load/store then perhaps add that
-------> otherwise you could just provide triggers for the basic functions (add x nodes or add edges with probability,...)
=======>The idea was to provide a simple applet from which the different tests could be launched,
=======>For each test we could easily change some settings such as the path's to the db/xml/dataset files
=======>Not to provide a GUI interface to the framework...


I kind of don't like how the neighbours/nodes are managed in our graph. Now we keep the neighbour nodes in each node 
and we keep the edges(that also contain nodes) in the graph. This is double the work. I would only keep edges to neighbours in the 
Node, so the graph only has a map of nodes. However it could be that the way it is now implemented was done for
a specific reason, so then you can ignore this...

Splitting the code into different files was an excellent decision. It had to happen sooner or later.

We can use an itterator pattern to implement different traversing strategy's.
---> Yea, we'll have to choose whether to implement using scala library traits Iterator or Traversable. 
---> I believe the assignment is hinting towards the use of Traversable. Adapting the code should be easy,
---> creating a wrapper class extending the trait and copying the foreach (currently called traverse) implementation.

For those like me already having an eclipse on there windows pc.
You can run an Ubigraph App in your familiar environment while outputting to the Linux Ubigraph Server.
The only thing you have to change is adding some libraries and:
UbigraphClient graph = new UbigraphClient("http://<LinuxUbigraphServer>:20738/RPC2");
It's working great so far :p

About

CPL Practicum 1

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages