1   package eu.fbk.shell.mdfsa.data.structures;
2   
3   import java.io.Serializable;
4   import java.util.ArrayList;
5   import java.util.HashMap;
6   import java.util.Iterator;
7   
8   public class Graph implements Serializable {
9   
10    private static final long serialVersionUID = 1L;
11    
12    private int nextNodeId;
13    private int numberOfEdges;
14    private HashMap<String, Long> labels;
15    private HashMap<Long, String> ids;
16    private HashMap<Long, Integer> markers;
17    private HashMap<Long, ArrayList<DomainEdge>> nodes;
18    
19    /* Maps dedicated to particular knowledge bases where a further level of semantic representation is requested */
20    private HashMap<String, ArrayList<Long>> wnWordSynsets;
21    
22    
23    public Graph() {
24      this.nextNodeId = 0;
25      this.labels = new HashMap<String, Long>();
26      this.ids = new HashMap<Long, String>();
27      this.nodes = new HashMap<Long, ArrayList<DomainEdge>>();
28      this.wnWordSynsets = new HashMap<String, ArrayList<Long>>();
29      this.markers = new HashMap<Long, Integer>();
30    }
31    
32    public HashMap<String, Long> getLabels() {
33      return this.labels;
34    }
35    public HashMap<Long, String> getIds() {
36      return this.ids;
37    }
38    public void setLabels(HashMap<String, Long> labels) {
39      this.labels = labels;
40    }
41    public HashMap<Long, ArrayList<DomainEdge>> getNodes() {
42      return this.nodes;
43    }
44    public void setNodes(HashMap<Long, ArrayList<DomainEdge>> nodes) {
45      this.nodes = nodes;
46    }
47    public HashMap<String, ArrayList<Long>> getWnWordSynsets() {
48      return wnWordSynsets;
49    }
50    public void setWnWordSynsets(HashMap<String, ArrayList<Long>> wnWordSynsets) {
51      this.wnWordSynsets = wnWordSynsets;
52    }
53  
54    
55    
56    public ArrayList<Long> getFeatureIds(String label) {
57      ArrayList<Long> feature = new ArrayList<Long>();
58      
59      /* Gets the id of the SenticNet concept */
60      Long currentFeatureId = this.labels.get(label);
61      if(currentFeatureId != null) {
62        feature.add(currentFeatureId);
63      }
64      
65      /* Gets the synsetIds from the WordNet knowledge */
66      ArrayList<Long> synsets = this.wnWordSynsets.get(label);
67      if(synsets != null) {
68        for(Long currentSynset: synsets) {
69          currentFeatureId = this.labels.get(String.valueOf(currentSynset));
70          if(currentFeatureId != null) {
71            feature.add(currentFeatureId);
72          }
73        }
74        
75      }
76      
77      return feature;
78    }
79    
80    
81    
82    /**
83     * Adds a new edge to the main knowledge graph
84     * @param source the label of the source concept
85     * @param target the label of the target concept
86     * @param wSource the weight of the edge target->source
87     * @param wTarget the weight of the edge source->target
88     */
89    public void addEdge(String source, String target, double wSource, double wTarget, int creator) {
90      
91      /* Checks if source and target concepts exist */
92      Long sourceId = this.labels.get(source);
93      Long targetId = this.labels.get(target);
94      
95      if(sourceId == null) {
96        sourceId = new Long(this.nextNodeId);
97        this.labels.put(source, sourceId);
98        this.ids.put(sourceId, source);
99        this.markers.put(sourceId, creator);
100       this.nextNodeId++;
101     }
102     
103     if(targetId == null) {
104       targetId = new Long(this.nextNodeId);
105       this.labels.put(target, targetId);
106       this.ids.put(targetId, target);
107       this.markers.put(targetId, creator);
108       this.nextNodeId++;
109     }
110     
111     /* Updates edges */
112     DomainEdge de1 = new DomainEdge(targetId, wTarget, creator);
113     this.updateEdge(sourceId, de1);
114     this.numberOfEdges++;
115     
116     /* The opposite edge is created only if the inverse weight is provided */
117     if(wSource != Double.MAX_VALUE) {
118       DomainEdge de2 = new DomainEdge(sourceId, wSource, creator);
119       this.updateEdge(targetId, de2);
120       this.numberOfEdges++;
121     }
122   }
123   
124   
125   /**
126    * Updates the edges map with the new data read during the training phase or inferred during the convergence phase
127    * @param nodeId the id of the node to be updated
128    * @param newEdge the edge containing the new information
129    */
130   private void updateEdge(long nodeId, DomainEdge newEdge) {
131     
132     boolean check = false;
133     DomainEdge e = null;
134     ArrayList<DomainEdge> edges = this.nodes.get(nodeId);
135     if(edges != null) {
136       for(int i = 0; i < edges.size(); i++) {
137         e = edges.get(i);
138         if(e.getNodeId() == newEdge.getNodeId()) {
139           check = true;
140           break;
141         }
142       }
143     }
144     
145     if(edges == null) {
146       edges = new ArrayList<DomainEdge>();
147     }
148     
149     if(check == false) {
150       edges.add(newEdge);
151     } else {
152       e.setWeight(newEdge.getWeight());
153     }
154     this.nodes.put(nodeId, edges);
155   }
156   
157   
158   /**
159    * Creates the relations between SenticNet and WordNet.
160    * Relations are created when only one WN synset is associated with a SN term.
161    * This, for avoiding the creation of ambiguous links.
162    */
163   public void createSenticNetWordNetRelations() {
164     Iterator markers = this.markers.keySet().iterator();
165     while(markers.hasNext()) {
166       long currentId = (Long) markers.next();
167       int currentMarker = (Integer) this.markers.get(currentId);
168       
169       /* Checks if the Id is marked with the SenticNet source (0) */
170       if(currentMarker == 0) {
171         String currentLabel = this.ids.get(currentId);
172         
173         /* Gets WN synsets associatd to the currentLabel and it checks if there is only one synset associated to the
174          * currentLabel in order to create the new relation. */
175         ArrayList<Long> synsets = this.wnWordSynsets.get(currentLabel);
176         //if(synsets != null && synsets.size() == 1) {
177         if(synsets != null) {
178           for(Long currentSynset: synsets) {
179             Long synsetIdGraph = (Long) this.labels.get(String.valueOf(currentSynset));
180             if(synsetIdGraph == null) {
181               continue;
182             }
183             
184             /* Updates edges */
185             DomainEdge de1 = new DomainEdge(synsetIdGraph, 1.0, 2);
186             this.updateEdge(currentId, de1);
187             this.numberOfEdges++;
188             DomainEdge de2 = new DomainEdge(currentId, 1.0, 2);
189             this.updateEdge(synsetIdGraph, de2);
190             this.numberOfEdges++;
191           }
192         }
193       }
194     }
195   }
196   
197   
198   
199   public int getNumberOfNodes() {
200     return nextNodeId;
201   }
202 
203   public int getNumberOfEdges() {
204     return numberOfEdges;
205   }
206   
207   
208   
209   /**
210    * Prints some statistics about the graph
211    */
212   public void printGraphStatistics() {
213     System.out.println("********************************************");
214     System.out.println("Number of node: " + this.labels.size());
215     System.out.println("Number of edges: " + this.numberOfEdges);
216   }
217 }