2021-01-29 06:31:58 -05:00
|
|
|
|
2023-09-25 14:41:00 -04:00
|
|
|
[![Arduino CI](https://github.com/RobTillaart/DistanceTable/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
|
2021-10-26 06:22:01 -04:00
|
|
|
[![Arduino-lint](https://github.com/RobTillaart/DistanceTable/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/DistanceTable/actions/workflows/arduino-lint.yml)
|
|
|
|
[![JSON check](https://github.com/RobTillaart/DistanceTable/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/DistanceTable/actions/workflows/jsoncheck.yml)
|
2023-09-25 14:41:00 -04:00
|
|
|
[![GitHub issues](https://img.shields.io/github/issues/RobTillaart/DistanceTable.svg)](https://github.com/RobTillaart/DistanceTable/issues)
|
|
|
|
|
|
|
|
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/DistanceTable/blob/master/LICENSE)
|
|
|
|
[![GitHub release](https://img.shields.io/github/release/RobTillaart/DistanceTable.svg?maxAge=3600)](https://github.com/RobTillaart/DistanceTable/releases)
|
|
|
|
[![PlatformIO Registry](https://badges.registry.platformio.org/packages/robtillaart/library/DistanceTable.svg)](https://registry.platformio.org/libraries/robtillaart/DistanceTable)
|
2021-01-29 06:31:58 -05:00
|
|
|
|
|
|
|
|
2022-07-22 16:43:52 -04:00
|
|
|
# DistanceTable
|
2017-07-27 10:24:22 -04:00
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
Arduino library to store a symmetrical distance table in less memory.
|
|
|
|
|
2017-07-27 10:24:22 -04:00
|
|
|
|
2020-11-27 05:10:47 -05:00
|
|
|
## Description
|
2017-07-27 10:24:22 -04:00
|
|
|
|
2020-11-27 05:10:47 -05:00
|
|
|
The DistanceTable library is a class that stores a symmetrical distance table
|
|
|
|
which is typically N x N entries in less memory space.
|
2021-10-26 06:22:01 -04:00
|
|
|
It uses (N x (N-1))/2 ("in a triangle") as an euclidean distance table is
|
2020-11-27 05:10:47 -05:00
|
|
|
symmetrical around its main diagonal.
|
|
|
|
Furthermore as the main diagonal are all zero it does not need to be stored either.
|
2017-07-27 10:24:22 -04:00
|
|
|
|
2020-11-27 05:10:47 -05:00
|
|
|
An ATMEL328 (Arduino) can store a 30 x 30 matrix = 900 floats in 1740 bytes,
|
2022-07-22 16:43:52 -04:00
|
|
|
where it would take 900 x 4 = 3600 bytes.
|
2020-11-27 05:10:47 -05:00
|
|
|
Within the 2K RAM of an Arduino one could store normally a 21 x 21 matrix (1764 bytes).
|
2022-07-22 16:43:52 -04:00
|
|
|
The class therefore saves around 50% of RAM.
|
|
|
|
The price is performance as it takes more time to access the elements.
|
|
|
|
|
2023-09-25 14:41:00 -04:00
|
|
|
#### Related
|
|
|
|
|
|
|
|
- https://github.com/RobTillaart/SparseArray
|
|
|
|
- https://github.com/RobTillaart/SparseMatrix
|
|
|
|
- https://www.codeproject.com/Tips/5368686/From-Linear-to-Upper-Triangular-Matrix-Indices
|
2017-07-27 10:24:22 -04:00
|
|
|
|
2021-01-29 06:31:58 -05:00
|
|
|
|
|
|
|
## Interface
|
|
|
|
|
2022-07-22 16:43:52 -04:00
|
|
|
```cpp
|
|
|
|
#include "DistanceTable.h"
|
|
|
|
```
|
|
|
|
|
|
|
|
### Constructor set get
|
|
|
|
|
2021-12-17 04:50:55 -05:00
|
|
|
- **DistanceTable(uint8_t size, float value = 0.0)** Constructor, allocates memory and
|
2022-07-22 16:43:52 -04:00
|
|
|
sets initial value to all elements.
|
|
|
|
If memory cannot be allocated, the size will be set to 0.
|
2023-09-25 14:41:00 -04:00
|
|
|
- **~DistanceTable()** Destructor, frees allocated memory.
|
2021-01-29 06:31:58 -05:00
|
|
|
- **void clear()** sets all entries to 0.0.
|
2022-07-22 16:43:52 -04:00
|
|
|
- **void setAll(float value)** sets all entries to value.
|
|
|
|
- **bool set(uint8_t x, uint8_t y, float value )** sets a value for (x,y) and automatically for (y, x).
|
|
|
|
Checks dimensions of x and y and if ```x == y``` value should be zero.
|
|
|
|
Returns true on success.
|
|
|
|
- **float get(uint8_t x, uint8_t y)** gets a value from (x, y). If ```x == y``` it will return 0.
|
|
|
|
|
|
|
|
|
|
|
|
### Statistics
|
2022-01-07 08:29:16 -05:00
|
|
|
|
2022-07-22 16:43:52 -04:00
|
|
|
- **float minimum(uint8_t &x, uint8_t &y)** Returns the minimum and first occurrence in x and y.
|
|
|
|
It skips all x == y pairs as these are 0.
|
|
|
|
- **float maximum(uint8_t &x, uint8_t &y)** Returns the maximum and first occurrence in x and y.
|
|
|
|
It skips all x == y pairs as these are 0.
|
|
|
|
- **float sum()** Returns the sum of the stored distances times 2 (== all distances)
|
|
|
|
It ignores the invert flag, as invert would make the sum 0.
|
|
|
|
- **float average()** Returns the average distance (== sum() / elements() ).
|
|
|
|
It ignores the invert flag, as invert would make the average 0.
|
|
|
|
It skips all x == y pairs as these are 0.
|
2022-01-07 08:29:16 -05:00
|
|
|
|
|
|
|
|
2022-07-22 16:43:52 -04:00
|
|
|
### Count
|
|
|
|
|
|
|
|
- **uint16_t count(float value, float epsilon = 0)** counts the number of occurrences of value.
|
|
|
|
As we are comparing floats the epsilon can set a margin for 'almost equal'. Default this is 0.
|
2022-01-07 08:29:16 -05:00
|
|
|
- **uint16_t countAbove(float value)** counts the number of occurrences larger than value.
|
|
|
|
- **uint16_t countBelow(float value)** counts the number of occurrences smaller than value.
|
|
|
|
|
|
|
|
Note 1: these 3 numbers do not always add up exactly as **count()** uses an epsilon where the
|
|
|
|
other two do not.
|
2022-07-22 16:43:52 -04:00
|
|
|
Note 2: the functions do not count the ```x == y``` diagonal.
|
|
|
|
So if you want to count the values == 0.0 you should add **dimension()**.
|
|
|
|
Behaviour might change in the future.
|
2022-01-07 08:29:16 -05:00
|
|
|
|
|
|
|
|
|
|
|
### Invert (experimental)
|
|
|
|
|
|
|
|
- **void setInvert(bool invert = false)** Set the invert flag.
|
|
|
|
- **bool getInvert()** returns the current value of the invert flag.
|
|
|
|
|
|
|
|
Normally the table is value symmetrical around the y == x diagonal.
|
|
|
|
With the invert flag, all values are inverted ==> **get(x, y) == -get(y, x)**.
|
|
|
|
This allows other uses for the table for only a few bytes of RAM.
|
2022-07-22 16:43:52 -04:00
|
|
|
The table becomes a **magnitude symmetrical distance table**.
|
2022-01-07 08:29:16 -05:00
|
|
|
|
|
|
|
The performance of the distance table is affected by the invert flag as most
|
|
|
|
functions need to test it.
|
|
|
|
In practice this means slower, especially when the flag is set to true.
|
|
|
|
|
|
|
|
Some application thoughts:
|
2023-09-25 14:41:00 -04:00
|
|
|
- difference in height between points on a route or map.
|
|
|
|
- energy levels e.g. transitions of electrons, other physics phenomena.
|
|
|
|
- transactions between players of a game, + for one is - for the other.
|
2022-01-07 08:29:16 -05:00
|
|
|
- hold a 2D colour space
|
|
|
|
|
2023-09-25 14:41:00 -04:00
|
|
|
Note: this functionality is not tested extensively.
|
2021-01-29 06:31:58 -05:00
|
|
|
|
|
|
|
|
|
|
|
### Debug
|
|
|
|
|
2022-07-22 16:43:52 -04:00
|
|
|
- **void dump(Print \* stream = &Serial)** dumps complete distance table, default to Serial.
|
|
|
|
Note in previous releases it dumped only a "triangle".
|
2021-01-29 06:31:58 -05:00
|
|
|
- **uint8_t dimension()** dimension of the table == parameter in constructor.
|
|
|
|
- **uint16_t elements()** amount of elements allocated.
|
2022-07-22 16:43:52 -04:00
|
|
|
- **uint16_t memoryUsed()** amount of memory used.
|
|
|
|
Typical ```elements() x sizeof(float)```.
|
2021-01-29 06:31:58 -05:00
|
|
|
|
|
|
|
|
2021-12-17 04:50:55 -05:00
|
|
|
## Operational
|
2021-01-29 06:31:58 -05:00
|
|
|
|
2021-12-17 04:50:55 -05:00
|
|
|
See examples.
|
2021-01-29 06:31:58 -05:00
|
|
|
|
|
|
|
|
2021-12-17 04:50:55 -05:00
|
|
|
## Future
|
2021-01-29 06:31:58 -05:00
|
|
|
|
2023-09-25 14:41:00 -04:00
|
|
|
#### Must
|
|
|
|
|
2021-12-17 04:50:55 -05:00
|
|
|
- improve documentation
|
2023-09-25 14:41:00 -04:00
|
|
|
|
|
|
|
|
|
|
|
#### Should
|
|
|
|
|
2022-07-22 16:43:52 -04:00
|
|
|
- improve unit tests
|
2023-09-25 14:41:00 -04:00
|
|
|
- rethink class hierarchy (see ideas below).
|
|
|
|
|
|
|
|
|
|
|
|
#### Could
|
|
|
|
|
2021-12-17 04:50:55 -05:00
|
|
|
- add examples
|
|
|
|
- Note: table can be used for other symmetrical 2D tables.
|
2022-01-07 08:29:16 -05:00
|
|
|
- And therefore include negative values
|
|
|
|
- investigate behaviour of **count()** functions a bit more.
|
|
|
|
- include diagonal?
|
2023-09-25 14:41:00 -04:00
|
|
|
- could the "non-inverted" distance table be a derived or base class?
|
|
|
|
- more performant
|
2022-01-07 08:29:16 -05:00
|
|
|
- diagonal not zero class,
|
2023-09-25 14:41:00 -04:00
|
|
|
- uses more bytes but allows also extra functionality while staying symmetrical.
|
|
|
|
- what if dimension(x) = 2x dimension(y) - non square tables.
|
|
|
|
- is there a spectrum of sparsity of a matrix?
|
|
|
|
- int64_t int32_t int16_t int8_t + unsigned variants? (8 variations? invert flag)
|
|
|
|
- Template class? (release 0.4.0 ?)
|
2022-01-07 08:29:16 -05:00
|
|
|
|
|
|
|
#### won't
|
|
|
|
|
2022-07-22 16:43:52 -04:00
|
|
|
- **clear()** could set all to NAN? is that better as it indicates unknown?
|
|
|
|
- setAll() let the user decide.
|
2022-01-07 08:29:16 -05:00
|
|
|
- Hamilton paths?
|
2022-07-22 16:43:52 -04:00
|
|
|
|
2017-07-27 10:24:22 -04:00
|
|
|
|
2023-09-25 14:41:00 -04:00
|
|
|
## Support
|
|
|
|
|
|
|
|
If you appreciate my libraries, you can support the development and maintenance.
|
|
|
|
Improve the quality of the libraries by providing issues and Pull Requests, or
|
|
|
|
donate through PayPal or GitHub sponsors.
|
|
|
|
|
|
|
|
Thank you,
|
|
|
|
|
|
|
|
|