0.2.0 TOPMAX

This commit is contained in:
Rob Tillaart 2023-06-17 18:01:24 +02:00
parent b425778412
commit ee213b9e34
9 changed files with 305 additions and 45 deletions

View File

@ -6,6 +6,21 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.2.0] - 2023-06-16
- breaking change!
- reverses the order of the maxima when requested.
- results in the top one always have index 0
- top position is independent of the size of the TOPMAX object.
- fix boundary bug **getValue() / getTag()** (index >= count).
- add allocation checks.
- **fill()** returns bool (true upon success)
- update unit tests
- update readme.md
- minor edits.
----
## [0.1.1] - 2023-05-20
- add **TOPMAXext**, holds a value + tag (e.g. timestamp or counter)
- add examples.
@ -13,7 +28,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- update readme.md
- minor edits.
## [0.1.0] - 2023-05-18
- initial version

View File

@ -36,6 +36,18 @@ be used more creatively e.g. 2x 16 bit numbers or even 32 booleans.
Any mapping is possible (but not part of the library).
#### 0.2.0 breaking change
Since version 0.2.0 the maxima is found with **getValue(index == 0)**.
In earlier versions the maxima was found with **index == count()**.
The advantage of this change is that independent of the size of the TOPMAX
object the true maxima will always at index == 0. So if you change your code
and the size of the TOPMAX object, far less code needs to be changed.
It also allows to have two or more TOPMAX objects of different size and use one
index to access both.
#### Links
- https://github.com/RobTillaart/TOPMAX
@ -54,17 +66,18 @@ Any mapping is possible (but not part of the library).
- **TOPMAX(uint8_t size = 5)** Constructor, defines the number of elements it can hold.
Default number of elements is 5. If **size** < 3 it will be set to 3.
The maximum size is currently 255.
The maximum size is currently 255, or less if there is not enough memory.
- **uint8_t count()** returns the number of elements in the internal array. 0.. size.
- **uint8_t size()** returns the maximum number of elements in the internal array.
- **void reset()** reset the internal counter to 0, logical clearing of the system.
- **bool add(float value)** add a value to the TOPMAX object to check of it needs to be
in the top N of maxima.
- **bool add(float value)** add a value to the TOPMAX object if it is in the top N of maxima.
If so the smallest element is removed.
Returns false if not added or if there was an allocation error.
- **float getValue(uint8_t index)** get an element of the internal array.
The index must be <= **count()**, if not the function currently returns **NaN**.
This may or may not be a valid value, so the user should guard the **index** parameter carefully.
- **bool fill(float value)** convenience function to fill the internal array
with a single value e.g. 0.
with a single value e.g. 0. Returns true on success.
#### TOPMAXext
@ -73,7 +86,7 @@ Derived from TOPMAX, extended with a tag field.
- **TOPMAXext(uint8_t size = 5)** Constructor, defines the number of elements it can hold.
Default number of elements is 5. If **size** < 3 it will be set to 3.
The maximum size is currently 255.
The maximum size is currently 255, or less if there is not enough memory.
- **bool add(float value, uint32_t tag)** add a value to the TOPMAXext object to check if
it needs to be in the top N of maxima. If so add the 32-bit **tag** too (at same index).
The 32-bit **tag** is typical an index, counter or timestamp, but any semantic is possible.
@ -88,19 +101,41 @@ with a single value e.g. 0. (tag idem).
#### Must
- keep functional in sync with TOPMIN.
- keep TOPMIN and TOPMAX functional in sync.
- improve documentation.
#### Should
- add unit tests.
- add more examples.
- add performance measurements.
- depends on size / and inserted values.
- for extended version if possible.
#### Could
- add more examples.
- example creative use of tag field.
- add error handling
- TOP_ERR_ALLOCATION
- TOP_ERR_INDEX
- TOP_NOT_ADDED
- TOP_OK
- int error; **int lastError()**
- create template class.
- **bool check(float value)** and **bool check(float value, uint32_t tag)**
- if (value < getValue(0)) or so.
- **inRange(value)**
- checks if this value would be added to the TOP-N
- **TOP** class, in which the condition can be set as parameter.
- a function() returning true or false when comparing 2 values.
- **bool hasValue(float value)** and **bool hasTag(uint32_t tag)**
- or **int getIndex(...)** duplicates?
#### Wont
- how to handle double/triple etc. entries with same value
- they are handled as unique elements, that is what I had in mind.
- optimize loops in **fill()** (maybe upon request)
- pointer math

View File

@ -1,7 +1,7 @@
//
// FILE: TOPMAX.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// VERSION: 0.2.0
// DATE: 2023-05-18
// PURPOSE: Arduino library to track top n maxima.
// URL: https://github.com/RobTillaart/TOPMAX
@ -45,6 +45,7 @@ void TOPMAX::reset()
bool TOPMAX::add(float value)
{
if (_arr == NULL) return false;
// initial
if (_count == 0)
{
@ -82,20 +83,22 @@ bool TOPMAX::add(float value)
}
float TOPMAX::getValue(uint8_t index)
{
if (index > _count) return NAN;
return _arr[index];
}
void TOPMAX::fill(float value)
bool TOPMAX::fill(float value)
{
if (_arr == NULL) return false;
for (int i = 0; i < _size; i++)
{
_arr[i] = value;
}
_count = _size;
return true;
}
float TOPMAX::getValue(uint8_t index)
{
if ((_arr == NULL) || (index >= _count)) return NAN;
return _arr[_count - 1 - index];
}
@ -117,6 +120,8 @@ TOPMAXext::~TOPMAXext()
bool TOPMAXext::add(float value, uint32_t tag)
{
if (_arr == NULL) return false;
if (_tag == NULL) return false;
// initial
if (_count == 0)
{
@ -156,25 +161,27 @@ bool TOPMAXext::add(float value, uint32_t tag)
_arr[i - 1] = value;
_tag[i - 1] = tag;
return true;
}
uint32_t TOPMAXext::getTag(uint8_t index)
{
if (index > _count) return 0xFFFFFFFF;
return _tag[index];
}
void TOPMAXext::fill(float value, uint32_t tag)
bool TOPMAXext::fill(float value, uint32_t tag)
{
if (_arr == NULL) return false;
if (_tag == NULL) return false;
for (int i = 0; i < _size; i++)
{
_arr[i] = value;
_tag[i] = tag;
}
_count = _size;
return true;
}
uint32_t TOPMAXext::getTag(uint8_t index)
{
if ((_tag == NULL) || (index >= _count)) return 0xFFFFFFFF;
return _tag[_count - 1 - index];
}

View File

@ -2,18 +2,18 @@
//
// FILE: TOPMAX.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// VERSION: 0.2.0
// DATE: 2023-05-18
// PURPOSE: Arduino library to track top n maxima.
// URL: https://github.com/RobTillaart/TOPMAX
#define TOPMAX_LIB_VERSION (F("0.1.1"))
#include "Arduino.h"
#define TOPMAX_LIB_VERSION (F("0.2.0"))
class TOPMAX
{
public:
@ -24,7 +24,7 @@ public:
uint8_t size();
void reset();
virtual bool add(float value);
virtual void fill(float value);
virtual bool fill(float value);
float getValue(uint8_t index);
@ -46,8 +46,8 @@ public:
~TOPMAXext();
bool add(float value, uint32_t tag);
bool fill(float value, uint32_t tag);
uint32_t getTag(uint8_t index);
void fill(float value, uint32_t tag);
private:
uint32_t * _tag;

View File

@ -0,0 +1,57 @@
//
// FILE: TOPMAX_duo.ino
// AUTHOR: Rob Tillaart
// PURPOSE: TOPMAX demo
// URL: https://github.com/RobTillaart/TOPMAX
// demo tracking the top 20 and
// only from the top 3 we keep the time stamp
#include "TOPMAX.h"
// saves about 60 bytes.
TOPMAXext tm_small(3);
TOPMAX tm_large(20);
uint32_t cnt = 0;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("TOPMAX_LIB_VERSION: ");
Serial.println(TOPMAX_LIB_VERSION);
Serial.println();
}
void loop()
{
int x = random(10000);
Serial.print(cnt++);
Serial.print("\t");
Serial.print(x);
Serial.print("\t");
for (int i = 0; i < tm_large.count(); i++)
{
Serial.print(tm_large.getValue(i));
if (i < tm_small.size())
{
Serial.print(" (");
Serial.print(tm_small.getTag(i));
Serial.print(")");
}
Serial.print("\t");
}
Serial.println();
tm_small.add(x, millis());
tm_large.add(x);
delay(100);
}
// -- END OF FILE --

View File

@ -0,0 +1,130 @@
//
// FILE: TOPMAX_performance.ino
// AUTHOR: Rob Tillaart
// PURPOSE: TOPMAX demo
// URL: https://github.com/RobTillaart/TOPMAX
#include "TOPMAX.h"
uint32_t start, stop;
uint32_t cnt = 0;
void setup()
{
Serial.begin(115200);
Serial.println(__FILE__);
Serial.print("TOPMAX_LIB_VERSION: ");
Serial.println(TOPMAX_LIB_VERSION);
Serial.println();
for (int sz = 1; sz <= 128; sz *= 2)
{
test_fill(sz);
}
Serial.println();
for (int sz = 1; sz <= 128; sz *= 2)
{
test_add(sz);
}
Serial.println();
for (int sz = 1; sz <= 128; sz *= 2)
{
test_fill_ext(sz);
}
Serial.println();
for (int sz = 1; sz <= 128; sz *= 2)
{
test_add_ext(sz);
}
Serial.println();
Serial.println("done...");
}
void loop()
{
}
void test_fill(uint8_t sz)
{
delay(100);
TOPMAX tm(sz);
start = micros();
for (int i = 0; i < 1000; i++) tm.fill(i);
stop = micros();
Serial.print("FILL\t");
Serial.print("size: ");
Serial.print(sz);
Serial.print("\t");
Serial.print(stop - start);
Serial.print("\t");
Serial.print((stop - start) * 0.001, 4);
Serial.println();
}
void test_add(uint8_t sz)
{
delay(100);
TOPMAX tm(sz);
start = micros();
for (int i = 0; i < 1000; i++) tm.add(i);
stop = micros();
Serial.print("ADD\t");
Serial.print("size: ");
Serial.print(sz);
Serial.print("\t");
Serial.print(stop - start);
Serial.print("\t");
Serial.print((stop - start) * 0.001, 4);
Serial.println();
}
void test_fill_ext(uint8_t sz)
{
delay(100);
TOPMAXext tm(sz);
start = micros();
for (int i = 0; i < 1000; i++) tm.fill(i, i);
stop = micros();
Serial.print("FILLext\t");
Serial.print("size: ");
Serial.print(sz);
Serial.print("\t");
Serial.print(stop - start);
Serial.print("\t");
Serial.print((stop - start) * 0.001, 4);
Serial.println();
}
void test_add_ext(uint8_t sz)
{
delay(100);
TOPMAXext tm(sz);
start = micros();
for (int i = 0; i < 1000; i++) tm.add(i, i);
stop = micros();
Serial.print("ADDext\t");
Serial.print("size: ");
Serial.print(sz);
Serial.print("\t");
Serial.print(stop - start);
Serial.print("\t");
Serial.print((stop - start) * 0.001, 4);
Serial.println();
}
// -- END OF FILE --

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/TOPMAX"
},
"version": "0.1.1",
"version": "0.2.0",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=TOPMAX
version=0.1.1
version=0.2.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library to track top n maxima.

View File

@ -75,7 +75,26 @@ unittest(test_add)
}
unittest(test_get)
unittest(test_getValue_I)
{
TOPMAX tm(5);
assertEqual(5, tm.size());
for (int i = 0; i < 10; i++)
{
assertNAN(tm.getValue(i));
}
for (int i = 0; i < 5; i++)
{
tm.add(i);
assertNotNAN(tm.getValue(i));
}
assertNAN(tm.getValue(5));
}
unittest(test_getValue_II)
{
TOPMAX tm(5);
assertEqual(5, tm.size());
@ -83,15 +102,13 @@ unittest(test_get)
for (int i = 0; i < 10; i++)
{
tm.add(i);
int idx = tm.count();
assertEqualFloat(i, tm.getValue(idx - 1), 0.001);
assertEqualFloat(i, tm.getValue(0), 0.001);
}
for (int i = 0; i < tm.count(); i++)
{
fprintf(stderr, "%f\t", tm.getValue(i));
}
fprintf(stderr, "\n");
}