Skip to content

Commit

Permalink
feat: rewrite PowerMeasure impls using DescriptiveStatistics
Browse files Browse the repository at this point in the history
Fixes #95
  • Loading branch information
metacosm committed Jul 8, 2024
1 parent 4cb0e19 commit ef55607
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 81 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,39 +1,59 @@
package net.laprun.sustainability.power.measure;

import java.time.Duration;
import java.util.ArrayList;
import java.util.stream.IntStream;

import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;

import net.laprun.sustainability.power.SensorMetadata;

public class OngoingPowerMeasure extends AbstractPowerMeasure {
public class OngoingPowerMeasure implements PowerMeasure {
private final SensorMetadata sensorMetadata;
private final DescriptiveStatistics[] measures;
private final DescriptiveStatistics total;
private final long startedAt;
private final double[] averages;
private double minTotal = Double.MAX_VALUE;
private double maxTotal;
private final double[] totals;
private final double[] averages;
private int samples;

public OngoingPowerMeasure(SensorMetadata sensorMetadata, long duration, long frequency) {
super(sensorMetadata, new ArrayList<>((int) (duration / frequency)));
public OngoingPowerMeasure(SensorMetadata sensorMetadata, Duration duration, Duration frequency) {
this.sensorMetadata = sensorMetadata;
startedAt = System.currentTimeMillis();
final var numComponents = metadata().componentCardinality();
totals = new double[numComponents];
averages = new double[numComponents];

final var initialWindow = (int) (duration.toMillis() / frequency.toMillis());
total = new DescriptiveStatistics(initialWindow);
this.measures = new DescriptiveStatistics[sensorMetadata.componentCardinality()];
for (int i = 0; i < measures.length; i++) {
measures[i] = new DescriptiveStatistics(initialWindow);
}
}

@Override
public int numberOfSamples() {
return samples;
}

@Override
public SensorMetadata metadata() {
return sensorMetadata;
}

public void recordMeasure(double[] components) {
final var recorded = new double[components.length];
System.arraycopy(components, 0, recorded, 0, components.length);
final var previousSize = numberOfSamples();
measures().add(recorded);

for (int i = 0; i < recorded.length; i++) {
totals[i] += recorded[i];
averages[i] = averages[i] == 0 ? recorded[i]
: (previousSize * averages[i] + recorded[i]) / numberOfSamples();
final var previousSize = samples;
samples++;
for (int component = 0; component < components.length; component++) {
final var componentValue = components[component];
measures[component].addValue(componentValue);
averages[component] = averages[component] == 0 ? componentValue
: (previousSize * averages[component] + componentValue) / samples;
}

// record min / max totals
final var recordedTotal = PowerMeasure.sumOfSelectedComponents(recorded, metadata().totalComponents());
final var recordedTotal = PowerMeasure.sumOfSelectedComponents(components, metadata().totalComponents());
total.addValue(recordedTotal);
if (recordedTotal < minTotal) {
minTotal = recordedTotal;
}
Expand All @@ -44,7 +64,7 @@ public void recordMeasure(double[] components) {

@Override
public double total() {
return PowerMeasure.sumOfSelectedComponents(totals, metadata().totalComponents());
return total.getSum();
}

public Duration duration() {
Expand All @@ -65,4 +85,19 @@ public double maxMeasuredTotal() {
public double[] averagesPerComponent() {
return averages;
}

public StdDev standardDeviations() {
final var cardinality = sensorMetadata.componentCardinality();
final var stdDevs = new double[cardinality];
IntStream.range(0, cardinality)
.parallel()
.forEach(component -> stdDevs[component] = measures[component].getStandardDeviation());

return new StdDev(total.getStandardDeviation(), stdDevs);
}

@Override
public double[] getMeasuresFor(int component) {
return measures[component].getValues();
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package net.laprun.sustainability.power.measure;

import java.time.Duration;
import java.util.List;
import java.util.stream.IntStream;

import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;

import net.laprun.sustainability.power.SensorMetadata;

Expand All @@ -28,6 +24,7 @@ static double sumOfSelectedComponents(double[] recorded, int... indices) {
return componentSum;
}

@SuppressWarnings("unused")
static String asString(PowerMeasure measure) {
final var durationInSeconds = measure.duration().getSeconds();
final var samples = measure.numberOfSamples();
Expand Down Expand Up @@ -62,30 +59,9 @@ default double average() {

double maxMeasuredTotal();

default StdDev standardDeviations() {
final var cardinality = metadata().componentCardinality();
final var totalComponents = metadata().totalComponents();
final DescriptiveStatistics[] perComponent = new DescriptiveStatistics[cardinality];
for (int i = 0; i < perComponent.length; i++) {
perComponent[i] = new DescriptiveStatistics();
}
final DescriptiveStatistics total = new DescriptiveStatistics();
IntStream.range(0, cardinality).parallel()
.forEach(component -> {
measures().stream().parallel().forEach(measure -> {
perComponent[component].addValue(measure[component]);
total.addValue(sumOfSelectedComponents(measure, totalComponents));
});
});

final var stdDevs = new double[cardinality];
for (int i = 0; i < perComponent.length; i++) {
stdDevs[i] = perComponent[i].getStandardDeviation();
}
return new StdDev(total.getStandardDeviation(), stdDevs);
}
StdDev standardDeviations();

List<double[]> measures();
double[] getMeasuresFor(int component);

/**
* Records the standard deviations for the aggregated energy comsumption value (as returned by {@link #total()}) and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,34 @@

import java.time.Duration;

public class StoppedPowerMeasure extends AbstractPowerMeasure {
import net.laprun.sustainability.power.SensorMetadata;

@SuppressWarnings("unused")
public class StoppedPowerMeasure implements PowerMeasure {
private final SensorMetadata sensorMetadata;
private final int samples;
private final Duration duration;
private final double total;
private final double min;
private final double max;
private final double[] averages;
private final StdDev standardDeviations;
private final double[][] measures;

public StoppedPowerMeasure(PowerMeasure powerMeasure) {
super(powerMeasure.metadata(), powerMeasure.measures());
this.sensorMetadata = powerMeasure.metadata();
this.duration = powerMeasure.duration();
this.total = powerMeasure.total();
this.min = powerMeasure.minMeasuredTotal();
this.max = powerMeasure.maxMeasuredTotal();
this.averages = powerMeasure.averagesPerComponent();
this.standardDeviations = powerMeasure.standardDeviations();
this.samples = powerMeasure.numberOfSamples();
final var cardinality = metadata().componentCardinality();
measures = new double[cardinality][samples];
for (int i = 0; i < cardinality; i++) {
measures[i] = powerMeasure.getMeasuresFor(i);
}
}

@Override
Expand All @@ -42,4 +56,24 @@ public double total() {
public double[] averagesPerComponent() {
return averages;
}

@Override
public int numberOfSamples() {
return samples;
}

@Override
public SensorMetadata metadata() {
return sensorMetadata;
}

@Override
public StdDev standardDeviations() {
return standardDeviations;
}

@Override
public double[] getMeasuresFor(int component) {
return measures[component];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.time.Duration;
import java.util.Map;

import org.junit.jupiter.api.Test;
Expand All @@ -23,7 +24,7 @@ public int componentCardinality() {
return 2;
}
};
final var measure = new OngoingPowerMeasure(metadata, 1, 500);
final var measure = new OngoingPowerMeasure(metadata, Duration.ofSeconds(1), Duration.ofMillis(500));

final var components = new double[metadata.componentCardinality()];
components[0] = m1c1;
Expand Down

0 comments on commit ef55607

Please sign in to comment.