1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Simple numerical statistical analysis and presentation
20 # A counter counts occurrences of things
21 # Use this instead of a `HashMap[E, Int]`
22 class Counter[E
: Object]
25 # Total number of counted occurrences
28 private var map
= new HashMap[E
, Int]
30 redef fun iterator
do return map
.iterator
32 # The number of counted occurrences of `e`
33 redef fun [](e
: E
): Int
36 if map
.has_key
(e
) then return map
[e
]
40 redef fun []=(e
: E
, value
: Int)
47 redef fun keys
do return map
.keys
49 redef fun values
do return map
.values
51 redef fun length
do return map
.length
53 redef fun is_empty
do return map
.is_empty
60 # Count one more occurrence of `e`
63 self.map
[e
] = self[e
] + 1
67 # Return an array of elements sorted by occurrences
70 var res
= map
.keys
.to_a
71 var sorter
= new CounterComparator[E
](self)
76 # The method used to display an element
77 # @toimplement by default just call `to_s` on the element
78 protected fun element_to_s
(e
: E
): String
83 # Display statistical information
87 print
" population: {list.length}"
88 if list
.is_empty
then return
89 print
" minimum value: {self[list.first]}"
90 print
" maximum value: {self[list.last]}"
91 print
" total value: {self.sum}"
92 print
" average value: {div(self.sum,list.length)}"
93 print
" distribution:"
96 var limit
= self[list
.first
]
98 if self[t
] > limit
then
99 print
" <={limit}: sub-population={count} ({div(count*100,list.length)}%); cumulated value={sum} ({div(sum*100,self.sum)}%)"
102 while self[t
] > limit
do
104 if limit
== 0 then limit
= 1
110 print
" <={limit}: sub-population={count} ({div(count*100,list.length)}%); cumulated value={sum} ({div(sum*100,self.sum)}%)"
113 # Display up to `count` most used elements and `count` least used elements
114 # Use `element_to_s` to display the element
115 fun print_elements
(count
: Int)
120 if list
.length
<= count
*2 then min
= list
.length
122 var t
= list
[list
.length-i-1
]
123 print
" {element_to_s(t)}: {self[t]} ({div(self[t]*100,self.sum)}%)"
125 if list
.length
<= count
*2 then return
128 var t
= list
[min-i-1
]
129 print
" {element_to_s(t)}: {self[t]} ({div(self[t]*100,self.sum)}%)"
133 # Return the element with the highest value
134 fun max
: nullable E
do
135 var max
: nullable Int = null
136 var elem
: nullable E
= null
138 if max
== null or v
> max
then
146 # Return the couple with the lowest value
147 fun min
: nullable E
do
148 var min
: nullable Int = null
149 var elem
: nullable E
= null
151 if min
== null or v
< min
then
161 if values
.is_empty
then return 0.0
162 return (sum
/ values
.length
).to_f
165 # The standard derivation of the counter values
166 fun std_dev
: Float do
169 for value
in map
.values
do
170 sum
+= (value
.to_f
- avg
).pow
(2.0)
172 return (sum
/ map
.length
.to_f
).sqrt
176 private class CounterComparator[E
: Object]
178 redef type COMPARED: E
179 var counter
: Counter[E
]
180 redef fun compare
(a
,b
) do return self.counter
.map
[a
] <=> self.counter
.map
[b
]
184 private fun show_counter
(c
: Counter[Int])
187 default_comparator
.sort
(list
)
189 print
" {e} -> {c[e]} times ({div(c[e]*100, c.sum)}%)"
193 # Display exhaustive metrics about the poset
196 var nb_greaters
= new Counter[E
]
197 var nb_direct_greaters
= new Counter[E
]
198 var nb_smallers
= new Counter[E
]
199 var nb_direct_smallers
= new Counter[E
]
200 var nb_direct_edges
= 0
204 nb_edges
+= ne
.greaters
.length
205 nb_direct_edges
+= ne
.direct_greaters
.length
206 nb_greaters
[n
] = ne
.greaters
.length
207 nb_direct_greaters
[n
] = ne
.direct_greaters
.length
208 nb_smallers
[n
] = ne
.smallers
.length
209 nb_direct_smallers
[n
] = ne
.direct_smallers
.length
211 print
"Number of nodes: {self.length}"
212 print
"Number of edges: {nb_edges} ({div(nb_edges,self.length)} per node)"
213 print
"Number of direct edges: {nb_direct_edges} ({div(nb_direct_edges,self.length)} per node)"
214 print
"Distribution of greaters"
215 nb_greaters
.print_summary
216 print
"Distribution of direct greaters"
217 nb_direct_greaters
.print_summary
218 print
"Distribution of smallers"
219 nb_smallers
.print_summary
220 print
"Distribution of direct smallers"
221 nb_direct_smallers
.print_summary
225 # Helper function to display `n/d` and handle division by 0
226 fun div
(n
: Int, d
: Int): String
228 if d
== 0 then return "na"
229 return ((100*n
/d
).to_f
/100.0).to_precision
(2)