forked from Cumulocity-IoT/analytics-builder-blocks-contrib
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Re-organize to blocks and cumulocity-blocks, add a DiscreateStatistic…
…s sample + test
- Loading branch information
Reed
committed
Jan 9, 2020
1 parent
70f355d
commit 931c596
Showing
5 changed files
with
236 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
/* | ||
* $Copyright (c) 2020 Software AG, Darmstadt, Germany and/or Software AG USA Inc., Reston, VA, USA, and/or its subsidiaries and/or its affiliates and/or their licensors.$ | ||
* Use, reproduction, transfer, publication or disclosure is prohibited except as specifically provided for in your License Agreement with Software AG | ||
*/ | ||
|
||
package apamax.analyticsbuilder.blocks; | ||
|
||
using apama.analyticsbuilder.BlockBase; | ||
using apama.analyticsbuilder.Activation; | ||
using apama.analyticsbuilder.Value; | ||
using apama.analyticsbuilder.TimerParams; | ||
using com.apama.exceptions.Exception; | ||
using apama.analyticsbuilder.L10N; | ||
using apama.analyticsbuilder.Promise; | ||
|
||
|
||
event DiscreteStatistics_$State { | ||
float sum; | ||
float sum_squared; | ||
integer count; | ||
float min; | ||
float max; | ||
|
||
|
||
action reset() { | ||
sum := 0.0; | ||
sum_squared := 0.0; | ||
count := 0; | ||
min := float.INFINITY; | ||
max := -float.INFINITY; | ||
} | ||
|
||
action update(float value) { | ||
sum := sum + value; | ||
sum_squared := sum_squared + value * value; | ||
count := count + 1; | ||
min := float.min(min, value); | ||
max := float.max(max, value); | ||
} | ||
} | ||
/** | ||
* Discrete Statistics | ||
* | ||
* Statistics for discrete measurements. | ||
* | ||
* Generates statistics - minimum, maximum, sum, count, mean and standard deviation for discrete time inputs. | ||
* | ||
* If the sample input is not connected, every re-evaluation will count, including when reset. If connected, block will | ||
* only update when a signal on the sample input is received. A sample and reset can co-incide, in which case the block | ||
* resets its state and then updates for the given value. | ||
* | ||
* @$blockCategory Aggregates | ||
*/ | ||
event DiscreteStatistics { | ||
|
||
BlockBase $base; | ||
|
||
|
||
|
||
/** | ||
* Calculates statistics. | ||
* @param $activation The current activation. | ||
* @param $input_value The input value. | ||
* @param $input_sample A new sample is provided. | ||
* @param $input_reset Reset the state of the block. | ||
*/ | ||
action $process(Activation $activation, float $input_value, boolean $input_reset, boolean $input_sample, DiscreteStatistics_$State $blockState) { | ||
if $blockState.count = 0 or $input_reset { | ||
$blockState.reset(); | ||
} | ||
if $base.getInputCount("sample") = 0 or $input_sample { | ||
$blockState.update($input_value); | ||
} | ||
$setOutput_sum($activation, $blockState.sum); | ||
$setOutput_count($activation, $blockState.count.toFloat()); | ||
$setOutput_min($activation, $blockState.min); | ||
$setOutput_max($activation, $blockState.max); | ||
float mean := $blockState.sum / $blockState.count.toFloat(); | ||
$setOutput_mean($activation, mean); | ||
$setOutput_standardDeviation($activation, (($blockState.sum_squared / $blockState.count.toFloat()) - (mean * mean)).sqrt()); | ||
} | ||
|
||
/** | ||
* Sum | ||
* | ||
* Sum of the received input values. | ||
*/ | ||
action<Activation,float> $setOutput_sum; | ||
/** | ||
* Count | ||
* | ||
* Count of the received input values. | ||
*/ | ||
action<Activation,float> $setOutput_count; | ||
/** | ||
* Mean | ||
* | ||
* Mean of the received input values. | ||
*/ | ||
action<Activation,float> $setOutput_mean; | ||
/** | ||
* Standard deviation | ||
* | ||
* Standard deviation of the received input values. | ||
*/ | ||
action<Activation,float> $setOutput_standardDeviation; | ||
/** | ||
* Minimum | ||
* | ||
* Minimum of the received input values. | ||
*/ | ||
action<Activation,float> $setOutput_min; | ||
/** | ||
* Maximum | ||
* | ||
* Maximum of the received input values. | ||
*/ | ||
action<Activation,float> $setOutput_max; | ||
|
||
/**Defines type for input reset.*/ | ||
constant string $INPUT_TYPE_reset := "pulse"; | ||
|
||
/**Defines type for input sample.*/ | ||
constant string $INPUT_TYPE_sample := "pulse"; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<pysysproject> | ||
<requires-pysys>1.3.0</requires-pysys> | ||
<requires-python>3</requires-python> | ||
|
||
|
||
<property name="ANALYTICS_BUILDER_SDK" value="${env.ANALYTICS_BUILDER_SDK}"/> | ||
|
||
|
||
<property name="SOURCE" value="${root}"/> | ||
<property root="testRootDir"/> | ||
<property environment="env"/> | ||
<property osfamily="osfamily"/> | ||
|
||
<property name="APAMA_HOME" value="${env.APAMA_HOME}"/> | ||
<property name="APAMA_WORK" value="${env.APAMA_WORK}"/> | ||
|
||
<property name="defaultAbortOnError" value="true"/> | ||
<property name="defaultIgnoreExitStatus" value="false"/> | ||
<property name="defaultEnvironsTempDir" value="self.output"/> | ||
<property name="redirectPrintToLogger" value="false"/> | ||
<property name="verboseWaitForSignal" value="true"/> | ||
|
||
<property name="shutdownApamaComponentsAfterTest" value="true"/> | ||
|
||
|
||
|
||
<runner classname="ApamaRunner" module="apama.runner"/> | ||
|
||
<path value="${ANALYTICS_BUILDER_SDK}/testframework"/> | ||
|
||
|
||
</pysysproject> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?xml version="1.0" standalone="yes"?> | ||
<pysystest type="auto" state="runnable"> | ||
|
||
<description> | ||
<title>Discrete stats: To check the basic working of the block</title> | ||
<purpose><![CDATA[ | ||
To check discrete statistics. | ||
]]> | ||
</purpose> | ||
</description> | ||
|
||
<classification> | ||
<groups> | ||
<group></group> | ||
</groups> | ||
</classification> | ||
|
||
<data> | ||
<class name="PySysTest" module="run"/> | ||
</data> | ||
|
||
<traceability> | ||
<requirements> | ||
<requirement id=""/> | ||
</requirements> | ||
</traceability> | ||
</pysystest> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# | ||
# $Copyright (c) 2019 Software AG, Darmstadt, Germany and/or Software AG USA Inc., Reston, VA, USA, and/or its subsidiaries and/or its affiliates and/or their licensors.$ | ||
# This file is licensed under the Apache 2.0 license - see https://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
|
||
from pysys.constants import * | ||
from apamax.analyticsbuilder.basetest import AnalyticsBuilderBaseTest | ||
|
||
|
||
class PySysTest(AnalyticsBuilderBaseTest): | ||
def execute(self): | ||
correlator = self.startAnalyticsBuilderCorrelator( | ||
blockSourceDir=f'{self.project.SOURCE}/blocks/') | ||
modelId = self.createTestModel('apamax.analyticsbuilder.blocks.DiscreteStatistics', inputs={'value':'float', 'sample':'pulse', 'reset':'pulse'}) | ||
self.sendEventStrings(correlator, | ||
self.timestamp(.9), | ||
self.inputEvent('value', 100, id=modelId), | ||
self.inputEvent('sample', 'true', id=modelId, eplType = 'boolean'), | ||
self.timestamp(1.9), | ||
self.inputEvent('value', 110, id=modelId), | ||
self.inputEvent('sample', 'true', id=modelId, eplType = 'boolean'), | ||
self.timestamp(2.9), | ||
self.inputEvent('value', 120, id=modelId), | ||
self.inputEvent('sample', 'true', id=modelId, eplType = 'boolean'), | ||
self.timestamp(3.9), | ||
self.inputEvent('value', 30, id=modelId), | ||
self.inputEvent('sample', 'true', id=modelId, eplType = 'boolean'), | ||
self.inputEvent('reset', 'true', id=modelId, eplType = 'boolean'), # reset and sample at same time : sum = mean = value | ||
self.timestamp(4.9), | ||
self.inputEvent('reset', 'true', id=modelId, eplType = 'boolean'), # reset on its own : sum = count = 0 (mean and std dev are NaN!) | ||
self.timestamp(6), | ||
) | ||
|
||
def validate(self): | ||
self.assertGrep('output.evt', expr=self.outputExpr('sum', 100, time=1)) | ||
self.assertGrep('output.evt', expr=self.outputExpr('count', 1, time=1)) | ||
self.assertGrep('output.evt', expr=self.outputExpr('sum', 100, time=1)) | ||
self.assertGrep('output.evt', expr=self.outputExpr('sum', 210, time=2)) | ||
self.assertGrep('output.evt', expr=self.outputExpr('sum', 330, time=3)) | ||
self.assertGrep('output.evt', expr=self.outputExpr('min', 100, time=3)) | ||
self.assertGrep('output.evt', expr=self.outputExpr('max', time=3)) | ||
self.assertGrep('output.evt', expr=self.outputExpr('mean', 110, time=3)) | ||
self.assertGrep('output.evt', expr=self.outputExpr('standardDeviation', 8.164965809277223, time=3)) | ||
self.assertGrep('output.evt', expr=self.outputExpr('sum', 30, time=4)) | ||
self.assertGrep('output.evt', expr=self.outputExpr('count', 1, time=4)) | ||
self.assertGrep('output.evt', expr=self.outputExpr('mean', 30, time=4)) | ||
self.assertGrep('output.evt', expr=self.outputExpr('standardDeviation', 0, time=4)) | ||
|
||
self.assertGrep('output.evt', expr=self.outputExpr('sum', 0, time=5)) |