1   package eu.fbk.shell.mdfsa.data.structures;
2   
3   import java.io.FileInputStream;
4   import java.io.ObjectInputStream;
5   import java.io.Serializable;
6   import java.util.ArrayList;
7   import java.util.HashMap;
8   import java.util.Iterator;
9   import java.util.Properties;
10  
11  public class DomainGraph {
12      
13    private String id;
14    private Properties prp;
15    private Graph graph;
16    private HashMap<Long, FuzzyMembership> polarities;
17    private HashMap<Long, ArrayList<Double>> conceptsConvergenceIterationsValues;
18    private HashMap<Long, Double> startPolarities;
19    private HashMap<Long, Double> tempInDomainStartPolarities;
20    private HashMap<Long, Double> tempOutDomainStartPolarities;
21    private HashMap<Long, Double> currentPolarities;
22    private HashMap<Long, Double> tokensCounter;
23    private HashMap<Long, Double> inDomainTokensCounter;
24    private HashMap<Long, Double> outDomainTokensCounter;
25    private double currentGraphConvergenceValue;
26    private double currentAveragePolarity;
27    private Iterator<Long> nodeIterator;
28    private int iteration;
29    private double propagationRate;
30    private double convergenceLimit;
31    private double deadzone;
32    private double annealingRate;
33    
34    
35    public DomainGraph(Properties prp) {
36      this.prp = prp;
37    }
38    
39    
40    public DomainGraph(String id, Properties prp, Graph g, double p, double c, double d, double a) {
41      this.id = id;
42      this.prp = prp;
43      this.graph = g;
44      this.polarities = new HashMap<Long, FuzzyMembership>();
45      this.conceptsConvergenceIterationsValues = new HashMap<Long, ArrayList<Double>>();
46      this.startPolarities = new HashMap<Long, Double>();
47      this.tempInDomainStartPolarities = new HashMap<Long, Double>();
48      this.tempOutDomainStartPolarities = new HashMap<Long, Double>();
49      this.currentPolarities = new HashMap<Long, Double>();
50      this.tokensCounter = new HashMap<Long, Double>();
51      this.inDomainTokensCounter = new HashMap<Long, Double>();
52      this.outDomainTokensCounter = new HashMap<Long, Double>();
53      this.currentGraphConvergenceValue = 0.0;
54      this.currentAveragePolarity = 0.0;
55      this.propagationRate = p;
56      this.convergenceLimit = c;
57      this.deadzone = d;
58      this.annealingRate = a;
59    }
60    
61    
62    /**
63     * Initializes the graph with the polarities representing the sentiment of each concept in the current domain
64     * @param instances
65     */
66    public void polarityInitialization(ArrayList<DatasetInstance> instances) {
67      
68      /*
69       * Puts the dataset information in the starting maps
70       */
71      //System.out.println("Reading dataset polarities.");
72      for(DatasetInstance di: instances) {
73        ArrayList<String> features = di.getFeatures();
74        int polarity = di.getPolarity();
75        
76        for(String currentFeature: features) {
77          
78          ArrayList<Long> featureIds = this.graph.getFeatureIds(currentFeature);
79          if(featureIds != null) {
80            for(Long featureId: featureIds) {
81              Double currentPolarity = this.startPolarities.get(featureId);
82              if(currentPolarity == null) {
83                currentPolarity = new Double(polarity);
84                this.startPolarities.put(featureId, currentPolarity);
85                this.currentPolarities.put(featureId, currentPolarity);
86              } else {
87                currentPolarity += polarity;
88                this.startPolarities.put(featureId, currentPolarity);
89                this.currentPolarities.put(featureId, currentPolarity);
90              }
91              
92              Double currentTokensCounter = this.tokensCounter.get(featureId);
93              if(currentTokensCounter == null) {
94                currentTokensCounter = new Double(1.0);
95                this.tokensCounter.put(featureId, currentTokensCounter);
96              } else {
97                currentTokensCounter++;
98                this.tokensCounter.put(featureId, currentTokensCounter);
99              }
100           }
101         }
102       }
103     }
104     
105     
106     /*
107      * Computes the starting polarities of each feature
108      */
109     //System.out.println("Computing starting polarities and creating starting fuzzy membership functions.");
110     for(long featureId: this.startPolarities.keySet()) {
111       double startPolarity = (double) this.startPolarities.get(featureId) / (double) this.tokensCounter.get(featureId);
112       this.startPolarities.put(featureId, startPolarity);
113       this.currentPolarities.put(featureId, startPolarity);
114       FuzzyMembership fm = new FuzzyMembership(-1.0, startPolarity, startPolarity, 1.0);
115       this.polarities.put(featureId, fm);
116     }
117   }
118   
119   
120   
121   
122   
123   /**
124    * Initializes the graph with the polarities representing the sentiment of each concept in the current domain
125    * @param instances
126    */
127   public void forcedPolarityInitialization(String concept, FuzzyMembership fm) {
128     
129     /*
130      * Puts the dataset information in the starting maps
131      */
132     ArrayList<Long> featureIds = this.graph.getFeatureIds(concept);
133     if(featureIds != null) {
134       for(Long featureId: featureIds) {
135         this.polarities.put(featureId, fm);
136       }
137     }
138   }
139   
140   
141   
142   
143   
144   
145   
146   
147   
148   
149   /**
150    * Initializes the graph with truth value related to the belonging of each concept to the current domain
151    * @param datasets the list of the domains
152    * @param instances the list of the training instances for each domain
153    * @param currentDomain the current domain
154    */
155   public void domainInitialization(String[] datasets, HashMap<String, ArrayList<DatasetInstance>> allInstances, String currentDomain) {
156     
157     /*
158      * Statistics variables
159      */
160     int featuresOverlap = 0;
161     
162     
163     /*
164      * Puts the dataset information in the starting maps
165      */
166     //System.out.println("Reading dataset polarities.");
167     for(String currentDataset: datasets) {
168       double polarity = 0.0;
169       if(currentDataset.compareTo(currentDomain) == 0) {
170         polarity = 1.0;
171       } else {
172         continue;
173         //polarity = -0.01 / (datasets.length - 1);
174         //polarity = -1.0;
175       }
176       
177       ArrayList<DatasetInstance> domainInstances = allInstances.get(currentDataset);
178       
179       for(DatasetInstance di: domainInstances) {
180         ArrayList<String> features = di.getFeatures();
181         for(String currentFeature: features) {
182           
183           ArrayList<Long> featureIds = this.graph.getFeatureIds(currentFeature);
184           if(featureIds != null) {
185             for(Long featureId: featureIds) {
186 
187               /*
188                * Generates the default values for the polarity maps
189                */
190               Double currentPolarity = this.startPolarities.get(featureId);
191               if(currentPolarity == null) {
192                 currentPolarity = new Double(polarity);
193                 this.startPolarities.put(featureId, currentPolarity);
194                 this.currentPolarities.put(featureId, currentPolarity);
195               } else {
196                 currentPolarity += polarity;
197                 this.startPolarities.put(featureId, currentPolarity);
198                 this.currentPolarities.put(featureId, currentPolarity);
199               }
200               
201               
202               /*
203                * Manages the in-domain and out-domain maps for the computation of the starting polarity values.
204                * The two different maps are used in order to manage separately the contributions coming from features
205                * defined in the in-domain and out-domain instances.
206                */
207               if(polarity > 0.0) {
208                 Double currentTokensCounter = this.inDomainTokensCounter.get(featureId);
209                 currentPolarity = this.tempInDomainStartPolarities.get(featureId);
210                 if(currentPolarity == null) {
211                   currentPolarity = new Double(polarity);
212                   this.tempInDomainStartPolarities.put(featureId, currentPolarity);
213                 } else {
214                   currentPolarity += polarity;
215                   this.tempInDomainStartPolarities.put(featureId, currentPolarity);
216                 }
217                 if(currentTokensCounter == null) {
218                   currentTokensCounter = new Double(1.0);
219                   this.inDomainTokensCounter.put(featureId, currentTokensCounter);
220                 } else {
221                   currentTokensCounter++;
222                   this.inDomainTokensCounter.put(featureId, currentTokensCounter);
223                 }
224               } else {
225                 Double currentTokensCounter = this.outDomainTokensCounter.get(featureId);
226                 currentPolarity = this.tempOutDomainStartPolarities.get(featureId);
227                 if(currentPolarity == null) {
228                   currentPolarity = new Double(polarity);
229                   this.tempOutDomainStartPolarities.put(featureId, currentPolarity);
230                 } else {
231                   currentPolarity += polarity;
232                   this.tempOutDomainStartPolarities.put(featureId, currentPolarity);
233                 }
234                 if(currentTokensCounter == null) {
235                   currentTokensCounter = new Double(1.0);
236                   this.outDomainTokensCounter.put(featureId, currentTokensCounter);
237                 } else {
238                   currentTokensCounter++;
239                   this.outDomainTokensCounter.put(featureId, currentTokensCounter);
240                 }
241               }
242               
243             }
244           }
245         }
246       }
247     }
248     
249     
250     
251     /*
252      * Computes the starting polarities of each feature
253      */
254     //System.out.println("Computing starting polarities and creating starting fuzzy membership functions.");
255     for(long featureId: this.startPolarities.keySet()) {
256       double inDomainPolarity;
257       double outDomainPolarity;
258       try {
259         inDomainPolarity = (double) this.tempInDomainStartPolarities.get(featureId) / 
260                            (double) this.inDomainTokensCounter.get(featureId);
261       } catch (NullPointerException e) {
262         inDomainPolarity = 0.0;
263       }
264       try {
265         outDomainPolarity = (double) this.tempOutDomainStartPolarities.get(featureId) / 
266                             (double) this.outDomainTokensCounter.get(featureId);
267       } catch (NullPointerException e) {
268         outDomainPolarity = 0.0;
269       }
270       
271       if(inDomainPolarity > 0.0 && outDomainPolarity < 0.0) {
272         featuresOverlap++;
273       }
274       
275       double startPolarity = inDomainPolarity + outDomainPolarity;
276       //double startPolarity = inDomainPolarity;
277       this.startPolarities.put(featureId, startPolarity);
278       this.currentPolarities.put(featureId, startPolarity);
279       FuzzyMembership fm = new FuzzyMembership(-1.0, startPolarity, startPolarity, 1.0);
280       this.polarities.put(featureId, fm);
281     }
282     //System.out.println(this.tempInDomainStartPolarities.size() + " - " + this.tempOutDomainStartPolarities.size() + " - " +
283     //                   featuresOverlap);
284   }
285   
286   
287   
288   
289   
290   
291   
292   
293   
294   /**
295    * Computes the fuzzy membership functions of each node of the graph starting from the values read in the dataset
296    * and by propagating them through the entire graph
297    */
298   public void polaritiesPropagation() {
299     this.iteration = 0;
300     
301     /* Prints some starting graph statistics */
302     int positive = 0;
303     int negative = 0;
304     int neutral = 0;
305     for(long featureId: this.currentPolarities.keySet()) {
306       double currentPolarity = this.currentPolarities.get(featureId);
307       if(currentPolarity > 0.0) {
308         positive++;
309       } else if(currentPolarity < 0.0) {
310         negative++;
311       } else {
312         neutral++;
313       }
314     }
315     //System.out.println("Positive: " + positive + " - Negative: " + negative + " - Neutral: " + neutral);
316     
317     
318     do {
319       this.nodeIterator = this.graph.getLabels().values().iterator();
320       int threadNumber = Integer.valueOf((String) this.prp.get("mdfsa.tasks"));
321       this.currentGraphConvergenceValue = 0.0;
322       this.currentAveragePolarity = 0.0;
323       NodeElaborator[] ne = new NodeElaborator[threadNumber];
324      
325       for(int i = 0; i < threadNumber; i++) {
326         ne[i] = new NodeElaborator(this, i);
327         ne[i].start();
328       }
329       for(int i = 0; i < threadNumber; i++) {
330         try {
331           ne[i].join();
332         } catch (InterruptedException e) {
333           e.printStackTrace();
334         }
335       }
336           
337       //System.out.println(this.currentGraphConvergenceValue);
338       this.iteration++;
339       this.propagationRate *= this.annealingRate;
340       this.applyRepulsionFactor();
341       //System.out.println(this.currentGraphConvergenceValue);
342     } while (this.currentGraphConvergenceValue > this.convergenceLimit && 
343              this.iteration < Integer.valueOf((String) this.prp.get("mdfsa.graph.iterationlimit")));
344     
345     
346     /* Prints some final graph statistics */
347     positive = 0;
348     negative = 0;
349     neutral = 0;
350     for(long featureId: this.currentPolarities.keySet()) {
351       double currentPolarity = this.currentPolarities.get(featureId);
352       if(currentPolarity > 0.0) {
353         positive++;
354       } else if(currentPolarity < 0.0) {
355         negative++;
356       } else {
357         neutral++;
358       }
359     }
360     //System.out.println("Iterations: " + iteration);
361     //System.out.println("Positive: " + positive + " - Negative: " + negative + " - Neutral: " + neutral);
362     
363     
364     /*
365      * Computes the FuzzyMembership functions of each concept
366      */
367     for(long featureId: this.currentPolarities.keySet()) {
368       Double conceptStartPolarity = this.startPolarities.get(featureId);
369       double conceptEndPolarity = 0.0;
370       if(conceptStartPolarity == null) {
371         conceptStartPolarity = 0.0;
372       }
373       ArrayList<Double> conceptConvergenceHistory = this.conceptsConvergenceIterationsValues.get(featureId);
374       
375       double avgPolarity = conceptStartPolarity;
376       double variance = 0.0;
377       if(conceptConvergenceHistory == null) {
378         variance = 2.0;
379       } else {
380         for(double value: conceptConvergenceHistory) {
381           avgPolarity += value;
382           conceptEndPolarity = value;
383         }
384         avgPolarity /= ((double) (conceptConvergenceHistory.size() + 1));
385         variance = Math.pow((conceptStartPolarity - avgPolarity), 2.0);
386         for(double value: conceptConvergenceHistory) {
387           variance += Math.pow((value - avgPolarity), 2.0);
388         }
389       }
390       
391       double a = 0.0;
392       double b = conceptStartPolarity;
393       double c = conceptEndPolarity;
394       double d = 0.0;
395       if(conceptStartPolarity > conceptEndPolarity) {
396         a = b;
397         b = c;
398         c = a;
399       }
400       a = b - (variance / 2.0);
401       d = c + (variance / 2.0);
402       if(a < -1.0) {
403         a = -1.0;
404       }
405       if(d > 1.0) {
406         d = 1.0;
407       }
408       
409       this.polarities.put(featureId, new FuzzyMembership(a, b, c, d));
410       //System.out.println(variance + " - " + Math.sqrt(variance));
411     }
412   }
413   
414   
415   
416   
417   /**
418    * Validates the learned graph on the predicting polarity test set
419    * @param instances the set of test instances
420    */
421   public double[] polarityTest(ArrayList<DatasetInstance> instances) {
422     //HashMap<String, Long> labels = this.graph.getLabels();
423     //System.out.println("Validating graph.");
424     
425     double deadzone = this.deadzone;
426     
427     int judged = 0;
428     double precision = 0.0;
429     double recall = 0.0;
430     
431     for(DatasetInstance di: instances) {
432       ArrayList<String> features = di.getFeatures();
433       int testPolarity = di.getPolarity();
434       
435       double inferredPolarity = 0.0;
436       double a = 0.0;
437       double b = 0.0;
438       double c = 0.0;
439       double d = 0.0;
440       int mappedFeatures = 0;
441       for(String currentFeature: features) {
442         //Long featureId = labels.get(currentFeature);
443         ArrayList<Long> featureIds = this.graph.getFeatureIds(currentFeature);
444         if(featureIds != null) {
445           for(Long featureId: featureIds) {
446             mappedFeatures++;
447             FuzzyMembership fm = this.polarities.get(featureId);
448             if(fm != null) {
449               inferredPolarity += fm.getCentroid();
450               a += fm.getA();
451               b += fm.getB();
452               c += fm.getC();
453               d += fm.getD();
454             }
455           }
456         }
457       }
458       a /= (double) mappedFeatures;
459       b /= (double) mappedFeatures;
460       c /= (double) mappedFeatures;
461       d /= (double) mappedFeatures;
462       //inferredPolarity /= (double) mappedFeatures;
463       inferredPolarity = (b + c) / 2.0;
464       //System.out.println("Test polarity: " + testPolarity + "; Inferred Polarity: " + inferredPolarity);
465       
466       int validationRestrictionFlag = Integer.valueOf(this.prp.getProperty("mdfsa.graph.validationrestriction"));
467       
468       if((validationRestrictionFlag == 2 && ((a < 0.0 && b > 0.0) || (c < 0.0 && d > 0.0) || (b < 0.0 && c > 0.0))) ||
469          (validationRestrictionFlag == 1 && (b < 0.0 && c > 0.0))) {
470         // do nothing
471       } else if((inferredPolarity < (0.0 - deadzone) && testPolarity == -1) ||
472                 (inferredPolarity > (0.0 + deadzone) && testPolarity == 1)) {
473         precision += 1.0;
474         judged++;
475       } else if(inferredPolarity < (0.0 - deadzone) || inferredPolarity > (0.0 + deadzone)) {
476         judged++;
477       }
478     }
479     
480     /* Print test results */
481     precision /= ((double)judged);
482     recall = ((double)judged) / (double)instances.size();
483     double fmeasure = 2.0 * ((precision * recall) / (precision + recall));
484     //System.out.println("********************************************");
485     //System.out.println("Precision: " + precision);
486     //System.out.println("Recall: " + recall);
487     //System.out.println("F-Measure: " + fmeasure);
488     
489     double[] results = new double[3];
490     results[0] = precision;
491     results[1] = recall;
492     results[2] = fmeasure;
493     return results;
494   }
495   
496   
497   
498   
499   /**
500    * Validates the learned graph on unknown polarity validation set by returning only the predicted polarity value
501    * @param instances the set of test instances
502    */
503   public ArrayList<DatasetInstance> polarityValidation(ArrayList<DatasetInstance> instances) {
504 
505     ArrayList<DatasetInstance> results = new ArrayList<DatasetInstance>();
506     double deadzone = this.deadzone;
507     
508     int judged = 0;
509     double precision = 0.0;
510     double recall = 0.0;
511     
512     for(DatasetInstance di: instances) {
513       ArrayList<String> features = di.getFeatures();
514       int testPolarity = di.getPolarity();
515       
516       double inferredPolarity = 0.0;
517       double a = 0.0;
518       double b = 0.0;
519       double c = 0.0;
520       double d = 0.0;
521       int mappedFeatures = 0;
522       for(String currentFeature: features) {
523         //Long featureId = labels.get(currentFeature);
524         ArrayList<Long> featureIds = this.graph.getFeatureIds(currentFeature);
525         if(featureIds != null) {
526           for(Long featureId: featureIds) {
527             mappedFeatures++;
528             FuzzyMembership fm = this.polarities.get(featureId);
529             if(fm != null) {
530               inferredPolarity += fm.getCentroid();
531               a += fm.getA();
532               b += fm.getB();
533               c += fm.getC();
534               d += fm.getD();
535             }
536           }
537         }
538       }
539       a /= (double) mappedFeatures;
540       b /= (double) mappedFeatures;
541       c /= (double) mappedFeatures;
542       d /= (double) mappedFeatures;
543 
544       inferredPolarity = (b + c) / 2.0;
545       di.setInferredPolarity(inferredPolarity);
546       results.add(di);
547     }
548     return results;
549   }
550   
551   
552   
553   /**
554    * Validates the learned graph on the predicting domain test set
555    * @param instances the set of test instances
556    */
557   public double domainTest(ArrayList<String> features, HashMap<String, DomainGraph> graphs) {
558     double inferredMembership = 0.0;
559     double a = 0.0;
560     double b = 0.0;
561     double c = 0.0;
562     double d = 0.0;
563     int mappedFeatures = 0;
564     for (String currentFeature : features) {
565       // Long featureId = labels.get(currentFeature);
566       ArrayList<Long> featureIds = this.graph.getFeatureIds(currentFeature);
567       if (featureIds != null) {
568         for (Long featureId : featureIds) {
569           Iterator<String> it = graphs.keySet().iterator();
570           ArrayList<Double> domainValues = new ArrayList<Double>();
571           while(it.hasNext()) {
572             String currentDomain = it.next();
573             DomainGraph domain = graphs.get(currentDomain);
574             double inferredValue = domain.domainTest(currentFeature, domain);
575             domainValues.add(inferredValue);
576           }
577           /*
578           int significativityFlag = this.getSignificativityFlag(domainValues);
579           if(significativityFlag == 0) {
580             continue;
581           }
582           */
583           mappedFeatures++;
584           FuzzyMembership fm = this.polarities.get(featureId);
585           if (fm != null) {
586             inferredMembership += fm.getCentroid();
587             a += fm.getA();
588             b += fm.getB();
589             c += fm.getC();
590             d += fm.getD();
591           }
592         }
593       }
594     }
595     inferredMembership /= (double) mappedFeatures;
596     a /= (double) mappedFeatures;
597     b /= (double) mappedFeatures;
598     c /= (double) mappedFeatures;
599     d /= (double) mappedFeatures;
600     return inferredMembership;
601   }
602   
603   
604   
605   
606   
607   /**
608    * Get the single feature graph polarity
609    * @param feature the feature to analyze
610    */
611   public double domainTest(String currentFeature, DomainGraph g) {
612     double inferredMembership = 0.0;
613     double a = 0.0;
614     double b = 0.0;
615     double c = 0.0;
616     double d = 0.0;
617     int mappedFeatures = 0;
618     
619     // Long featureId = labels.get(currentFeature);
620     ArrayList<Long> featureIds = g.getGraph().getFeatureIds(currentFeature);
621     if (featureIds != null) {
622       for (Long featureId : featureIds) {
623         mappedFeatures++;
624         FuzzyMembership fm = g.getPolarities().get(featureId);
625         if (fm != null) {
626           inferredMembership += fm.getCentroid();
627           a += fm.getA();
628           b += fm.getB();
629           c += fm.getC();
630           d += fm.getD();
631         }
632       }
633     }
634 
635     inferredMembership /= (double) mappedFeatures;
636     a /= (double) mappedFeatures;
637     b /= (double) mappedFeatures;
638     c /= (double) mappedFeatures;
639     d /= (double) mappedFeatures;
640     return inferredMembership;
641   }
642   
643   
644   
645   
646   
647   
648   
649   
650   
651   /*
652    * Methods for the elaboration and propagation of data 
653    */
654   
655   
656   public synchronized Long getNextNodeId() {
657     Long nextNodeId = null;
658     if(this.nodeIterator.hasNext()) {
659       nextNodeId = this.nodeIterator.next();
660     }
661     return nextNodeId; 
662   }
663   
664   public synchronized void updatePolarities(long nodeId, FuzzyMembership fm) {
665     return;
666   }
667   
668   
669   /**
670    * Updates the value representing the total polarities update of the graph during the running iteration. 
671    * @param contribution the contribution given by the changes of each node.
672    */
673   public synchronized void updateCurrentGraphConvergenceValue(double contribution) {
674     this.currentGraphConvergenceValue += contribution;
675     return;
676   }
677   
678   
679  
680   
681   /**
682    * Saves the new polarity value computed for a node. Such value is saved both in the map
683    * containing the current polarities of each node as well as in the map containing the historical convergence
684    * values of each node.
685    * @param nodeId the id of the node.
686    * @param value the new polarity value of the node.
687    */
688   public synchronized void setIterationResult(long nodeId, double value) {
689     
690     /* Updates the current polarity value of the node */
691     this.currentPolarities.put(nodeId, value);
692     
693     /* Updates the iteration value list of the node */
694     ArrayList<Double> iterationValues = this.conceptsConvergenceIterationsValues.get(nodeId);
695     if(iterationValues == null) {
696       iterationValues = new ArrayList<Double>();
697     }
698     iterationValues.add(value);
699     this.conceptsConvergenceIterationsValues.put(nodeId, iterationValues);
700     
701     /*  Updates the value representing the average polarity of the graph after the execution of a complete iteration. */
702     this.currentAveragePolarity += value;
703     
704     return;
705   }
706   
707   
708   
709   private void applyRepulsionFactor() {
710     this.currentAveragePolarity /= this.graph.getLabels().values().size();
711     int numberOfNodes = this.graph.getNumberOfNodes();
712     int numberOfEdges = this.graph.getNumberOfEdges();
713     
714     Iterator<Long> it = this.currentPolarities.keySet().iterator();
715     while(it.hasNext()) {
716       Long nodeId = (Long) it.next();
717       Double value = this.currentPolarities.get(nodeId);
718       
719       /* Applies the repulsion factor */
720       double lambda = this.propagationRate;
721       //double lambda = ((double) numberOfEdges / (((double) numberOfNodes * (double) numberOfNodes) - (double) numberOfNodes));
722       if(value != null) {
723         value +=  lambda * (value - this.currentAveragePolarity);
724       }
725       
726       /* Updates the current polarity value of the node */
727       this.currentPolarities.put(nodeId, value);
728     }
729   }
730   
731   
732   /* Computes the difference between the two top values of polarities between a set them 
733    * for deciding if the difference is statistically significant or not.
734    */
735   private int getSignificativityFlag(ArrayList<Double> values) {
736     int flag = 0;
737     double first = Double.MIN_VALUE;
738     double second = Double.MIN_VALUE;
739     for(Double d: values) {
740       if(d > first) {
741         first = d;
742       } else if(d > second) {
743         second = d;
744       }
745     }
746     
747     if((first - second) > 0.1) {
748       flag = 1;
749     }
750     
751     return flag;
752   }
753   
754   
755   
756   /**
757    * Internal class used as thread for speeding-up the propagation of information through the graph
758    */
759   private class NodeElaborator extends Thread implements Serializable {
760     
761     private static final long serialVersionUID = 1L;
762     
763     private DomainGraph dg;
764     private double propagationRate;
765     private Iterator<Long> nodes;
766     private int threadId;
767     
768     public NodeElaborator(DomainGraph dg, int threadId) {
769       this.dg = dg;
770       this.propagationRate = this.dg.propagationRate;
771       this.nodes = this.dg.nodeIterator;
772       this.threadId = threadId;
773     }
774     
775     /*
776     private Long getNextNodeId() {
777       Long nextNodeId = null;
778       if(this.nodes.hasNext()) {
779         nextNodeId = this.nodes.next();
780       }
781       return nextNodeId; 
782     }
783     */
784     
785     public void run() {
786       Long nextNodeId = this.dg.getNextNodeId();
787       //Long nextNodeId = this.getNextNodeId();
788       //System.out.println("Thread: " + this.threadId + " - Node: " + nextNodeId);
789       
790       /*
791        * Updates node polarity
792        */
793       while(nextNodeId != null) {
794         //System.out.println("Thread: " + this.threadId + " - Node: " + nextNodeId);
795         //System.out.print(this.dg.graph.getIds().get(nextNodeId));
796         
797         /* Gets all edges */
798         ArrayList<DomainEdge> des = this.dg.graph.getNodes().get(nextNodeId);
799         if(des != null) {
800           
801           /* Gets current polarity */
802           Double startNodePolarity = this.dg.currentPolarities.get(nextNodeId);
803           Double actualPropagationRate = this.propagationRate;
804           if(startNodePolarity == null) {
805             startNodePolarity = 0.0;
806             actualPropagationRate = 1.0;
807           }
808           
809           //System.out.print(" (" + startNodePolarity + "): ");
810           /* Loops through all edges and reads the current polarity of each of them */
811           double edgesPolarities = 0.0;
812           for(DomainEdge de: des) {
813             long edgeNodeId = de.getNodeId();
814             //System.out.print(this.dg.graph.getIds().get(edgeNodeId));
815             Double currentEdgePolarity = this.dg.currentPolarities.get(edgeNodeId);
816             if(currentEdgePolarity != null) {
817               //System.out.print(" (" + currentEdgePolarity + ")");
818               edgesPolarities += (currentEdgePolarity * de.getWeight());
819             }
820             //System.out.print(" - ");
821           }
822           
823           /* Current node polarity is "merged" with the one coming from the neighborhoods */
824           double currentNodePolarity = (startNodePolarity * (1 - actualPropagationRate)) +
825                                        ((edgesPolarities / des.size()) * actualPropagationRate);
826           //System.out.println(currentNodePolarity);
827           
828           /* Updates the total propagation difference of the graph */
829           this.dg.updateCurrentGraphConvergenceValue(Math.abs(startNodePolarity - currentNodePolarity));
830           
831           /* Updates the polarity of the node and its convergence history */
832           this.dg.setIterationResult(nextNodeId, currentNodePolarity);
833         }
834         
835         nextNodeId = this.dg.getNextNodeId();
836       }
837     }
838   }
839 
840   
841 
842   /**
843    * Produces a serializable version of the DomainGraph object
844    */
845   public SerializableDomainGraph getSerializableDomainGraph() {
846     SerializableDomainGraph sdg = new SerializableDomainGraph();
847     sdg.setPrp(this.prp);
848     sdg.setGraph(this.graph);
849     sdg.setPolarities(this.polarities);
850     sdg.setConceptsConvergenceIterationsValues(this.conceptsConvergenceIterationsValues);
851     sdg.setStartPolarities(this.startPolarities);
852     sdg.setTempInDomainStartPolarities(this.tempInDomainStartPolarities);
853     sdg.setTempOutDomainStartPolarities(this.tempOutDomainStartPolarities);
854     sdg.setCurrentPolarities(this.currentPolarities);
855     sdg.setTokensCounter(this.tokensCounter);
856     sdg.setInDomainTokensCounter(this.inDomainTokensCounter);
857     sdg.setOutDomainTokensCounter(this.outDomainTokensCounter);
858     sdg.setCurrentGraphConvergenceValue(this.currentGraphConvergenceValue);
859     sdg.setCurrentAveragePolarity(this.currentAveragePolarity);
860     sdg.setIteration(this.iteration);
861     sdg.setPropagationRate(this.propagationRate);
862     sdg.setConvergenceLimit(this.convergenceLimit);
863     sdg.setDeadzone(this.deadzone);
864     sdg.setAnnealingRate(this.annealingRate);
865     return sdg;
866   }
867   
868   
869   /** Initializes the DomainGraph object with serialized data **/
870   public void setDomainGraphFromSerializedData(String currentDataset, String modelPath, String type) {
871     try {
872       ObjectInputStream objectInputStream = new ObjectInputStream(
873           new FileInputStream(modelPath + currentDataset + "." + type + ".mdfsa"));
874       SerializableDomainGraph sdg = (SerializableDomainGraph) objectInputStream.readObject();
875       this.prp = sdg.getPrp();
876       this.graph = sdg.getGraph();
877       this.polarities = sdg.getPolarities();
878       this.conceptsConvergenceIterationsValues = sdg.getConceptsConvergenceIterationsValues();
879       this.startPolarities = sdg.getStartPolarities();
880       this.tempInDomainStartPolarities = sdg.getTempInDomainStartPolarities();
881       this.tempOutDomainStartPolarities = sdg.getTempOutDomainStartPolarities();
882       this.currentPolarities = sdg.getCurrentPolarities();
883       this.tokensCounter = sdg.getTokensCounter();
884       this.inDomainTokensCounter = sdg.getInDomainTokensCounter();
885       this.outDomainTokensCounter = sdg.getOutDomainTokensCounter();
886       this.currentGraphConvergenceValue = sdg.getCurrentGraphConvergenceValue();
887       this.currentAveragePolarity = sdg.getCurrentAveragePolarity();
888       this.iteration = sdg.getIteration();
889       this.propagationRate = sdg.getPropagationRate();
890       this.convergenceLimit = sdg.getConvergenceLimit();
891       this.deadzone = sdg.getDeadzone();
892       this.annealingRate = sdg.getAnnealingRate();
893     } catch (Exception e) {
894       e.printStackTrace();
895     }
896   }
897   
898   
899   public void setDomainGraphFromSerializedData(String modelPath) {
900     try {
901       ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(modelPath));
902       SerializableDomainGraph sdg = (SerializableDomainGraph) objectInputStream.readObject();
903       this.prp = sdg.getPrp();
904       this.graph = sdg.getGraph();
905       this.polarities = sdg.getPolarities();
906       this.conceptsConvergenceIterationsValues = sdg.getConceptsConvergenceIterationsValues();
907       this.startPolarities = sdg.getStartPolarities();
908       this.tempInDomainStartPolarities = sdg.getTempInDomainStartPolarities();
909       this.tempOutDomainStartPolarities = sdg.getTempOutDomainStartPolarities();
910       this.currentPolarities = sdg.getCurrentPolarities();
911       this.tokensCounter = sdg.getTokensCounter();
912       this.inDomainTokensCounter = sdg.getInDomainTokensCounter();
913       this.outDomainTokensCounter = sdg.getOutDomainTokensCounter();
914       this.currentGraphConvergenceValue = sdg.getCurrentGraphConvergenceValue();
915       this.currentAveragePolarity = sdg.getCurrentAveragePolarity();
916       this.iteration = sdg.getIteration();
917       this.propagationRate = sdg.getPropagationRate();
918       this.convergenceLimit = sdg.getConvergenceLimit();
919       this.deadzone = sdg.getDeadzone();
920       this.annealingRate = sdg.getAnnealingRate();
921       objectInputStream.close();
922     } catch (Exception e) {
923       e.printStackTrace();
924     }
925   }
926 
927 
928   public HashMap<Long, FuzzyMembership> getPolarities() {
929     return polarities;
930   }
931 
932 
933   public void setPolarities(HashMap<Long, FuzzyMembership> polarities) {
934     this.polarities = polarities;
935   }
936 
937 
938   public Graph getGraph() {
939     return graph;
940   }
941 
942 
943   public void setGraph(Graph graph) {
944     this.graph = graph;
945   }
946 }