+# A Metric that collects float datas
+#
+# Used sor summarization
+class FloatMetric
+ super Metric
+
+ redef type VAL: Float
+
+ # `FloatMetric` uses a Map to store values in intern.
+ protected var values_cache = new HashMap[ELM, VAL]
+
+ redef fun values do return values_cache
+
+ redef fun clear do values_cache.clear
+
+
+ redef fun sum do
+ var sum = 0.0
+ for v in values.values do
+ if v.is_nan then continue
+ sum += v
+ end
+ return sum
+ end
+
+ redef fun max do
+ assert not values.is_empty
+ var max: nullable Float = null
+ var elem: nullable ELM = null
+ for e, v in values do
+ if max == null or v > max then
+ max = v
+ elem = e
+ end
+ end
+ return elem.as(not null)
+ end
+
+ redef fun min do
+ assert not values.is_empty
+ var min: nullable Float = null
+ var elem: nullable ELM = null
+ for e, v in values do
+ if min == null or v < min then
+ min = v
+ elem = e
+ end
+ end
+ return elem.as(not null)
+ end
+
+ redef fun avg do
+ if values.is_empty then return 0.0
+ return sum / values.length.to_f
+ end
+
+ redef fun std_dev do
+ var sum = 0.0
+ for value in values.values do
+ if value.is_nan then continue
+ sum += (value - avg).pow(2.to_f)
+ end
+ return (sum / values.length.to_f).sqrt
+ end
+
+ redef fun above_threshold do
+ var above = new HashSet[ELM]
+ var threshold = threshold
+ for element, value in values do
+ if value > threshold then above.add(element)
+ end
+ return above
+ end
+
+ redef fun to_console(indent, colors) do
+ super
+ if colors then
+ print "{"\t" * indent} sum: {sum}".light_gray
+ else
+ print "{"\t" * indent} sum: {sum}"
+ end
+ end
+end
+
+# A MetricSet is a metric holder
+#
+# It purpose is to be extended with a metric collect service
+class MetricSet
+
+ # Type of element measured by this `MetricSet`.
+ type ELM: Object
+
+ # Metrics to compute
+ var metrics: Set[Metric] = new HashSet[Metric]
+
+ # Add a metric to the set
+ fun register(metrics: Metric...) do for metric in metrics do self.metrics.add(metric)
+
+ # Clear all results for all metrics
+ fun clear do for metric in metrics do metric.clear
+
+ # Collect all metrics for this set of class
+ fun collect(elements: Set[ELM]) do
+ for metric in metrics do metric.collect(elements)
+ end
+
+ # Pretty print the resuls in console
+ fun to_console(indent: Int, colors: Bool) do
+ for metric in metrics do metric.to_console(indent, colors)
+ end
+
+ # Export the metric set in CSV format
+ fun to_csv: CsvDocument do
+ var csv = new CsvDocument
+
+ csv.format = new CsvFormat('"', ';', "\n")
+
+ # set csv headers
+ csv.header.add("entry")
+ for metric in metrics do csv.header.add(metric.name)
+
+ # collect all entries to merge metric results
+ var entries = new HashSet[ELM]
+ for metric in metrics do
+ for entry in metric.values.keys do entries.add(entry)
+ end
+
+ # collect results
+ for entry in entries do
+ var line = [entry.to_s]
+ for metric in metrics do
+ if metric.has_element(entry) then
+ line.add(metric[entry].to_s)
+ else
+ line.add("n/a")
+ end
+ end
+ csv.records.add(line)
+ end
+ return csv