/*
* Copyright (C) 2015 Adrien Guille <adrien.guille@univ-lyon2.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package main.java.fr.ericlab.sondy.algo.eventdetection.mabed;
import main.java.fr.ericlab.sondy.core.app.AppParameters;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import org.graphstream.algorithm.ConnectedComponents;
import org.graphstream.algorithm.ConnectedComponents.ConnectedComponent;
import org.graphstream.graph.Edge;
import org.graphstream.graph.Graph;
import org.graphstream.graph.Node;
import org.graphstream.graph.implementations.SingleGraph;
/**
*
* @author Adrien GUILLE, ERIC Lab, University of Lyon 2
* @email adrien.guille@univ-lyon2.fr
*/
public class MABEDEventGraph implements Serializable {
public Graph graph;
public Graph redundancyGraph;
public HashMap<String,MABEDEvent> duplicatedEvents;
double maximumScore;
double sigma;
public MABEDEventGraph(double ms, Double sig){
sigma = sig;
graph = new SingleGraph("");
redundancyGraph = new SingleGraph("");
maximumScore = ms;
duplicatedEvents = new HashMap<>();
}
public int addEvent(MABEDEvent event){
int added = 0;
boolean redundant = false;
if(graph.getNode(event.mainTerm) != null){
for(MABEDWeightedTerm wt : event.relatedTerms.list){
Node wtNode = graph.getNode(wt.term);
if(wtNode != null){
if(wtNode.getAttribute("ui.class").equals("mainTerm") && wtNode.hasEdgeFrom(graph.getNode(event.mainTerm).toString())){
MABEDEvent event1 = getEvent(wtNode);
double intersection = Math.max(event.I.intersectionProportion(event1.I), event1.I.intersectionProportion(event.I));
if(intersection > sigma){
redundant = true;
duplicatedEvents.put(event.mainTerm,event);
duplicatedEvents.put(event1.mainTerm,event1);
// new way of managing redundancy
if(redundancyGraph.getNode(event1.mainTerm) == null){
redundancyGraph.addNode(event1.mainTerm);
}
if(redundancyGraph.getNode(event.mainTerm) == null){
redundancyGraph.addNode(event.mainTerm);
}
if(redundancyGraph.getEdge(event.mainTerm+"-"+event1.mainTerm) == null){
redundancyGraph.addEdge(event.mainTerm+"-"+event1.mainTerm, event.mainTerm, event1.mainTerm, false);
}
}
}
}
}
}
if(!redundant){
if(event.mainTerm != null){
if(graph.getNode(event.mainTerm) == null){
graph.addNode(event.mainTerm);
}
graph.getNode(event.mainTerm).addAttributes(event.getMainTermAttributes());
graph.getNode(event.mainTerm).setAttribute("ui.size",20+(event.score/maximumScore)*10);
graph.getNode(event.mainTerm).addAttribute("ui.label", "["+AppParameters.dataset.corpus.convertTimeSliceToDay(event.I.timeSliceA)+"::"+AppParameters.dataset.corpus.convertTimeSliceToDay(event.I.timeSliceB)+"]:"+event.mainTerm);
graph.getNode(event.mainTerm).addAttribute("anomaly",event.anomaly);
for(MABEDWeightedTerm wt : event.relatedTerms.list){
if(wt.term != null){
if(graph.getNode(wt.term)==null){
graph.addNode(wt.term);
graph.getNode(wt.term).addAttribute("ui.label", wt.term);
graph.getNode(wt.term).setAttribute("ui.class","relatedTerm");
}
graph.addEdge("["+event.I.timeSliceA+":"+event.I.timeSliceB+"]"+event.mainTerm+"-"+wt.term,wt.term,event.mainTerm,true);
graph.getEdge("["+event.I.timeSliceA+":"+event.I.timeSliceB+"]"+event.mainTerm+"-"+wt.term).addAttribute("weight", wt.weight);
}
}
}
added = 1;
}
return added;
}
public MABEDEventList identifyConnectedComponents(){
ConnectedComponents ccs = new ConnectedComponents(redundancyGraph);
ccs.setCountAttribute("component");
int i = 0;
MABEDEventList globalEvents = new MABEDEventList();
for (ConnectedComponent cc : ccs) {
MABEDEventList ccEvents = new MABEDEventList();
for(Node node : cc.getEachNode()){
MABEDEvent event = duplicatedEvents.get(node.getId());
ccEvents.add(event);
removeEvent(event);
}
ccEvents.sort();
MABEDEvent mainEvent = ccEvents.list.pop();
MABEDEvent globalEvent = mainEvent.merge(ccEvents);
globalEvents.add(globalEvent);
addEvent(globalEvent);
i++;
}
return globalEvents;
}
public void removeEvent(MABEDEvent event){
Node mainNode = graph.getNode(event.mainTerm);
if(mainNode != null){
if(mainNode.getAttribute("ui.class").equals("mainTerm")){
Collection<Edge> edges = mainNode.getEnteringEdgeSet();
if(edges != null){
for(Edge edge : edges){
if(edge != null){
// remove obsolete edge
graph.removeEdge(edge);
if(edge.getSourceNode().getDegree() == 0){
graph.removeNode(edge.getSourceNode().toString());
}
}
}
}
if(mainNode.getOutDegree() == 0){
graph.removeNode(mainNode);
}else{
mainNode.setAttribute("ui.class", "relatedTerm");
}
}
}
}
public void replaceEvent(Node nodeT0, MABEDEvent t1){
nodeT0.setAttribute("ui.class","relatedTerm");
Collection<Edge> edges = nodeT0.getEnteringEdgeSet();
graph.addNode(t1.mainTerm);
graph.getNode(t1.mainTerm).addAttributes(t1.getMainTermAttributes());
graph.getNode(t1.mainTerm).setAttribute("ui.size",20+(t1.score/maximumScore)*10);
graph.getNode(t1.mainTerm).addAttribute("ui.label", "["+AppParameters.dataset.corpus.convertTimeSliceToDay(t1.I.timeSliceA)+"::"+AppParameters.dataset.corpus.convertTimeSliceToDay(t1.I.timeSliceB)+"]:"+t1.mainTerm);
graph.getNode(t1.mainTerm).setAttribute("anomaly",t1.anomaly);
if(edges != null){
for(Edge edge : edges){
if(edge != null){
// remove obsolete edge
graph.removeEdge(edge);
// add edge toward the new main term
if(!t1.mainTerm.contains(edge.getSourceNode().getId())){
String edgeId = "["+t1.I.timeSliceA+":"+t1.I.timeSliceB+"]"+t1.mainTerm+"-"+edge.getSourceNode().getId();
graph.addEdge(edgeId,edge.getSourceNode().getId(),t1.mainTerm,true);
graph.getEdge(edgeId).addAttribute("weight", edge.getAttribute("weight"));
}
if(edge.getSourceNode().getDegree() == 0){
graph.removeNode(edge.getSourceNode().toString());
}
}
}
}
graph.removeNode(nodeT0);
for(MABEDWeightedTerm wt : t1.relatedTerms.list){
if(wt.term != null){
if(graph.getNode(wt.term)==null){
graph.addNode(wt.term);
graph.getNode(wt.term).addAttribute("ui.label", wt.term);
graph.getNode(wt.term).setAttribute("ui.class","relatedTerm");
}
if(graph.getEdge("["+t1.I.timeSliceA+":"+t1.I.timeSliceB+"]"+t1.mainTerm+"-"+wt.term) == null){
graph.addEdge("["+t1.I.timeSliceA+":"+t1.I.timeSliceB+"]"+t1.mainTerm+"-"+wt.term,wt.term,t1.mainTerm,true);
}
graph.getEdge("["+t1.I.timeSliceA+":"+t1.I.timeSliceB+"]"+t1.mainTerm+"-"+wt.term).addAttribute("weight", wt.weight);
}
}
// if(nodeT0.getDegree() == 0){
// System.out.println(" - "+nodeT0.getId()+" is a leaf node.");
// graph.removeNode(nodeT0);
// }
}
public MABEDEvent getEvent(Node mainNode){
MABEDEvent event = new MABEDEvent();
if(mainNode.getAttribute("ui.class")!=null && mainNode.getAttribute("ui.class").equals("mainTerm")){
event = new MABEDEvent(mainNode.getId(), new MABEDTimeInterval((String) mainNode.getAttribute("I")), (double) mainNode.getAttribute("score"), (ArrayList<Double>) mainNode.getAttribute("anomaly"));
for(Edge edge : mainNode.getEnteringEdgeSet()){
event.relatedTerms.add(new MABEDWeightedTerm(edge.getSourceNode().getId(), (double) edge.getAttribute("weight")));
}
}
return event;
}
public MABEDEventList toEventList(){
MABEDEventList events = new MABEDEventList();
events.timeSliceLength = AppParameters.dataset.corpus.timeSliceLength;
events.corpusStart = new Timestamp(AppParameters.dataset.corpus.start.getTime());
for(Node node : graph){
if(node.getAttribute("ui.class")!=null && node.getAttribute("ui.class").equals("mainTerm")){
MABEDEvent event = new MABEDEvent(node.getId(), new MABEDTimeInterval((String) node.getAttribute("I")), (double) node.getAttribute("score"), (ArrayList<Double>) node.getAttribute("anomaly"));
for(Edge edge : node.getEnteringEdgeSet()){
event.relatedTerms.add(new MABEDWeightedTerm(edge.getSourceNode().getId(), (double) edge.getAttribute("weight")));
}
events.add(event);
}
}
events.sort();
return events;
}
}