nitg: add more info (for -v)
[nit.git] / src / counter.nit
index e7a7a9d..67b79fc 100644 (file)
 # Simple numerical statistical analysis and presentation
 module counter
 
-# A counter counts occurence of things
+import poset
+
+# A counter counts occurrences of things
 # Use this instead of a HashMap[E, Int]
 class Counter[E: Object]
-       # Total number of counted occurences
+       super Map[E, Int]
+
+       # Total number of counted occurrences
        var total: Int = 0
 
        private var map = new HashMap[E, Int]
 
-       # The number of counted occurences of `e'
-       fun [](e: E): Int
+       # The number of counted occurrences of `e'
+       redef fun [](e: E): Int
        do
                var map = self.map
                if map.has_key(e) then return map[e]
                return 0
        end
 
-       # Count one more occurence of `e'
+       redef fun []=(e: E, value: Int)
+       do
+               total -= self[e]
+               self.map[e] = value
+               total += value
+       end
+
+       redef fun keys do return map.keys
+
+       redef fun values do return map.values
+
+       # Count one more occurrence of `e'
        fun inc(e: E)
        do
                self.map[e] = self[e] + 1
                total += 1
        end
 
-       # Return an array of elements sorted by occurences
+       # Return an array of elements sorted by occurrences
        fun sort: Array[E]
        do
                var res = map.keys.to_a
@@ -47,6 +62,36 @@ class Counter[E: Object]
                #res.sort !cmp a, b = map[a] <=> map[b]
                return res
        end
+
+       # Display statistical information
+       fun print_summary
+       do
+               var list = self.sort
+               print " population: {list.length}"
+               if list.is_empty then return
+               print " minimum value: {self[list.first]}"
+               print " maximum value: {self[list.last]}"
+               print " total value: {self.total}"
+               print " average value: {div(self.total,list.length)}"
+               print " distribution:"
+               var count = 0
+               var sum = 0
+               var limit = self[list.first]
+               for t in list do
+                       if self[t] > limit then
+                               print "  <={limit}: sub-population={count} ({div(count*100,list.length)}%); cumulated value={sum} ({div(sum*100,self.total)}%)"
+                               count = 0
+                               sum = 0
+                               while self[t] > limit do
+                                       limit = limit * 2
+                                       if limit == 0 then limit = 1
+                               end
+                       end
+                       count += 1
+                       sum += self[t]
+               end
+               print "  <={limit}: sub-population={count} ({div(count*100,list.length)}%); cumulated value={sum} ({div(sum*100,self.total)}%)"
+       end
 end
 
 private class CounterSorter[E: Object]
@@ -55,6 +100,48 @@ private class CounterSorter[E: Object]
        redef fun compare(a,b) do return self.counter.map[a] <=> self.counter.map[b]
 end
 
+redef class POSet[E]
+       private fun show_counter(c: Counter[Int])
+       do
+               var list = c.sort
+               (new ComparableSorter[Int]).sort(list)
+               for e in list do
+                       print " {e} -> {c[e]} times ({div(c[e]*100, c.total)}%)"
+               end
+       end
+
+       # Display exhaustive metrics about the poset
+       fun print_metrics
+       do
+               var nb_greaters = new Counter[E]
+               var nb_direct_greaters = new Counter[E]
+               var nb_smallers = new Counter[E]
+               var nb_direct_smallers = new Counter[E]
+               var nb_direct_edges = 0
+               var nb_edges = 0
+               for n in self do
+                       var ne = self[n]
+                       nb_edges += ne.greaters.length
+                       nb_direct_edges += ne.direct_greaters.length
+                       nb_greaters[n] = ne.greaters.length
+                       nb_direct_greaters[n] = ne.direct_greaters.length
+                       nb_smallers[n] = ne.smallers.length
+                       nb_direct_smallers[n] = ne.direct_smallers.length
+               end
+               print "Number of nodes: {self.length}"
+               print "Number of edges: {nb_edges} ({div(nb_edges,self.length)} per node)"
+               print "Number of direct edges: {nb_direct_edges} ({div(nb_direct_edges,self.length)} per node)"
+               print "Distribution of greaters"
+               nb_greaters.print_summary
+               print "Distribution of direct greaters"
+               nb_direct_greaters.print_summary
+               print "Distribution of smallers"
+               nb_smallers.print_summary
+               print "Distribution of direct smallers"
+               nb_direct_smallers.print_summary
+       end
+end
+
 # Helper function to display n/d and handle division by 0
 fun div(n: Int, d: Int): String
 do