0.1.2 SparseMatrix

This commit is contained in:
rob tillaart 2022-07-14 17:28:24 +02:00
parent 84b8c6b223
commit 7aefcd0252
13 changed files with 230 additions and 54 deletions

View File

@ -8,4 +8,6 @@ compile:
- m4
- esp32
- esp8266
# - mega2560
# - mega2560
libraries:
- "SHT85"

View File

@ -13,44 +13,78 @@ Arduino library for sparse matrices.
## Description
SparseMatrix is an **experimental** library to implement sparse matrices on an Arduino.
SparseMatrix is an **experimental** library to implement
two dimensional sparse matrices (of floats) on an Arduino.
A sparse matrix is a matrix with mostly zeros and a low percentage non-zero values.
The purpose of this library is efficient storage in memory.
The maximum matrix that can be represented is 255 x 255
with a maximum of 255 non-zero elements.
This would just fit in an UNO's 2K memory.
with a theoretical maximum of 65535 non-zero elements.
In practice the library limits this to 1000 non-zero elements.
Note: 255 elements would still fit in an UNO's 2K memory.
The library does not hold the dimensions of the matrix (at least in 0.1.0)
Note: the library does not do matrix math operations.
The purpose of the library is efficient storage in memory.
It does not do math operations except sum().
Note: the library does not hold the dimensions of the matrix
and cannot check these.
Relates to https://github.com/RobTillaart/distanceTable
Relates somewhat to https://github.com/RobTillaart/distanceTable
#### Implementation
The implementation is based on 3 arrays holding ``` x, y, value``` where value is float.
In the future other datatypes should be possible.
The implementation is based on 3 arrays holding ``` x, y, value```
where value is float, and x and y are uint8_t.
That are 6 bytes per element.
The number of elements that the sparse matrix object can hold are
given as parameter to the constructor.
If the space cannot be allocated the size is set to zero.
In the future other data types should be possible.
#### Performance
The elements are not kept sorted or indexed so optimizations are possible
but not investigated yet.
The elements are not kept sorted or indexed so optimizations might be
possible but are not investigated yet.
There is however a test sketch to monitor the performance of
the most important functions.
Accessing elements internally is done with a linear search,
which becomes (much) slower if the number of elements is increasing.
This means that although in theory there can be 65535 elements,
in practice a few 100 can already become annoyingly slow.
To keep performance a bit the library has a limit build in.
Check the .h file for **SPARSEMATRIX_MAX_SIZE 1000**
## Interface
- **SparseMatrix(uint8_t size)** constructor.
```cpp
#include "SparseMatrix.h"
```
### Constructor + meta
- **SparseMatrix(uint16_t size)** constructor.
Parameter is the maximum number of elements in the sparse matrix.
- **uint8_t size()** maximum number of elements.
- **uint8_t count()** current number of elements in the matrix.
Note this number is limited to **SPARSEMATRIX_MAX_SIZE 1000**.
If the space requested cannot be allocated size will be set to 0.
- **uint16_t size()** maximum number of elements.
If this is zero, a problem occurred with allocation happened.
- **uint16_t count()** current number of elements in the matrix.
Should be between 0 and size.
- **float sum()** sum of all elements ( > 0 ) in the matrix.
- **void clear()** resets the matrix to all zero's again.
### Access
- **bool set(uint8_t x, uint8_t y, float value)** gives an element in the matrix a value.
If the value is set to zero, it is removed from the internal store.
Returns false if the internal store is full, true otherwise.
- **float get(uint8_t x, uint8_t y)** returns the value in the matrix.
- **bool add(uint8_t x, uint8_t y, float value)** adds a value to an element in the matrix.
- **bool add(uint8_t x, uint8_t y, float value)** adds value to an element in the matrix.
If needed a new internal element is created.
If the sum is zero, the element is removed from the internal store.
Returns false if the internal store is full, true otherwise.
@ -64,32 +98,33 @@ Returns false if the internal store is full, true otherwise.
- 1, 2, 3 (RGB), 4 byte integer or 8 byte doubles
- struct, complex number
- etc
- add examples
- 2D histogram e.g. temperature vs humidity
- N queens game.
- investigate optimizations.
- should **set()** and **add()** return the number of free places?
- no hard code and more informative than just a bool.
- investigate performance optimizations
- sort
- linked list, tree, hashing?
- can **set()** and **add()** be merged?
- add link in distanceTable repo
- uint16_t size for larger platforms.
- max matrix still 255 x 255 but more elements <> 0.
#### new functions
#### Functions
- walk through the elements?
- first -> next; last -> prev.
- first() -> next(); optional last() -> prev().
#### won't
- should **set()** and **add()** return the number of free places?
- more informative than just a bool.
- One looses the info that the operation was successful
- set a zero threshold ?
- if (abs(x) < TH) element is considered zero => remove
- not portable to template version (sum() is not either!)
- user can do this.
- math
- determinant?
- M x M
- diagonal?
- add examples
- N queens game.
- battleship game
- minesweeper game
- nice exercise

View File

@ -1,24 +1,32 @@
//
// FILE: SparseMatrix.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// VERSION: 0.1.2
// DATE: 2022-07-12
// PURPOSE: Arduino library for sparse matrices
// URL: https://github.com/RobTillaart/SparseMatrix
//
// HISTORY:
// 0.1.0 2022-07-12 initial version
// 0.1.1 2022-07-13 add clear();
// add add(x, y, value);
// fix set(x, y, 0);
// 0.1.2 2022-07-14 increase size to uint16_t
// add SPARSEMATRIX_MAX_SIZE
// improve documentation
#include "SparseMatrix.h"
SparseMatrix::SparseMatrix(uint8_t sz)
SparseMatrix::SparseMatrix(uint16_t sz)
{
_count = 0;
_size = sz;
if ( _size > SPARSEMATRIX_MAX_SIZE)
{
_size = SPARSEMATRIX_MAX_SIZE;
}
_x = (uint8_t *) malloc(sz);
_y = (uint8_t *) malloc(sz);
_value = (float *) malloc(sz * sizeof(float));
@ -37,13 +45,13 @@ SparseMatrix::~SparseMatrix()
}
uint8_t SparseMatrix::size()
uint16_t SparseMatrix::size()
{
return _size;
}
uint8_t SparseMatrix::count()
uint16_t SparseMatrix::count()
{
return _count;
}
@ -58,7 +66,7 @@ void SparseMatrix::clear()
float SparseMatrix::sum()
{
float _sum = 0;
for (int i = 0; i < _count; i++)
for (uint16_t i = 0; i < _count; i++)
{
_sum += _value[i];
}
@ -68,7 +76,7 @@ float SparseMatrix::sum()
bool SparseMatrix::set(uint8_t x, uint8_t y, float value)
{
int pos = findPos(x, y);
int32_t pos = findPos(x, y);
// existing element
if (pos > -1)
{
@ -104,7 +112,7 @@ bool SparseMatrix::set(uint8_t x, uint8_t y, float value)
bool SparseMatrix::add(uint8_t x, uint8_t y, float value)
{
int pos = findPos(x, y);
int32_t pos = findPos(x, y);
// existing element
if (pos > -1)
{
@ -137,7 +145,7 @@ bool SparseMatrix::add(uint8_t x, uint8_t y, float value)
float SparseMatrix::get(uint8_t x, uint8_t y)
{
int pos = findPos(x, y);
int32_t pos = findPos(x, y);
if (pos > -1)
{
return _value[pos];
@ -146,13 +154,18 @@ float SparseMatrix::get(uint8_t x, uint8_t y)
}
int SparseMatrix::findPos(uint8_t x, uint8_t y)
//////////////////////////////////////////////////////
//
// PRIVATE
//
int32_t SparseMatrix::findPos(uint8_t x, uint8_t y)
{
for (int i = 0; i < _count; i++)
// linear search - not optimized.
for (uint16_t i = 0; i < _count; i++)
{
if ((_x[i] == x) && (_y[i] == y))
{
return i;
return (int32_t)i;
}
}
return -1;
@ -161,3 +174,4 @@ int SparseMatrix::findPos(uint8_t x, uint8_t y)
// -- END OF FILE --

View File

@ -2,25 +2,30 @@
//
// FILE: SparseMatrix.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// VERSION: 0.1.2
// DATE: 2022-07-12
// PURPOSE: Arduino library for sparse matrices
// URL: https://github.com/RobTillaart/SparseMatrix
//
#include "Arduino.h"
#define SPARSEMATRIX_LIB_VERSION (F("0.1.1"))
#define SPARSEMATRIX_LIB_VERSION (F("0.1.2"))
#ifndef SPARSEMATRIX_MAX_SIZE
#define SPARSEMATRIX_MAX_SIZE 1000
#endif
class SparseMatrix
{
public:
SparseMatrix(uint8_t sz);
SparseMatrix(uint16_t sz);
~SparseMatrix();
uint8_t size();
uint8_t count();
uint16_t size();
uint16_t count();
float sum();
void clear();
@ -34,16 +39,16 @@ public:
private:
int _size = 0;
int _count = 0;
uint16_t _size = 0;
uint16_t _count = 0;
uint8_t *_x = NULL;
uint8_t *_y = NULL;
float *_value = NULL;
// returns index of x,y if in set
// returns index of x, y if in set
// otherwise -1
int findPos(uint8_t x, uint8_t y);
int32_t findPos(uint8_t x, uint8_t y);
};

View File

@ -0,0 +1,92 @@
//
// FILE: sparse_matrix_2D_histogram.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo 2D
// URL: https://github.com/RobTillaart/SparseMatrix
//
// TOPVIEW SHT85 (check datasheet)
// +-------+
// +-----\ | SDA 4 -----
// | +-+ ----+ GND 3 -----
// | +-+ ----+ +5V 2 -----
// +-----/ | SCL 1 -----
// +-------+
#include "SparseMatrix.h"
#include "SHT85.h"
#define SHT85_ADDRESS 0x44
SHT85 sht;
SparseMatrix sm(40);
uint32_t lastTime = 0;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println(__FILE__);
Serial.print("SHT_LIB_VERSION: \t");
Serial.println(SHT_LIB_VERSION);
Serial.print("SPARSEMATRIX_LIB_VERSION: \t");
Serial.println(SPARSEMATRIX_LIB_VERSION);
sm.clear();
Wire.begin();
sht.begin(SHT85_ADDRESS);
Wire.setClock(100000);
}
void loop()
{
if (millis() - lastTime > 10000)
{
lastTime = millis();
dump(20, 10, 0);
}
sht.read();
uint8_t x = round(sht.getHumidity()) - 45; // adjust if needed
uint8_t y = round(sht.getTemperature()) - 20; // adjust if needed
// Serial.print(x);
// Serial.print(" ");
// Serial.print(y);
// Serial.print("\n");
sm.add(x, y, 1);
delay(1000);
}
void dump(uint8_t sx, uint8_t sy, uint8_t dm)
{
Serial.println();
Serial.print("DUMP\t");
Serial.print(sm.size());
Serial.print("\t");
Serial.print(sm.count());
Serial.print("\t");
Serial.print(sx);
Serial.print("x");
Serial.print(sy);
Serial.print("\t");
Serial.println(sm.sum());
for (int y = 0; y < sy; y++)
{
for (int x = 0; x < sx; x++)
{
Serial.print(sm.get(x, y), dm);
Serial.print('\t');
}
Serial.println();
}
Serial.println();
}
// -- END OF FILE --

View File

@ -2,6 +2,7 @@
// FILE: sparse_matrix_demo.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// URL: https://github.com/RobTillaart/SparseMatrix
#include "SparseMatrix.h"

View File

@ -2,6 +2,7 @@
// FILE: sparse_matrix_max.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo max size matrix.
// URL: https://github.com/RobTillaart/SparseMatrix
#include "SparseMatrix.h"

View File

@ -0,0 +1,15 @@
sparse_matrix_performance.ino
0.1.2
20
0
set 20x : 428
redo 20x : 380
full 20x : 532
add 20x : 452
get 20x : 244
9.00
sum 20x : 160
clr 20x : 4

View File

@ -2,7 +2,7 @@
// FILE: sparse_matrix_performance.ino
// AUTHOR: Rob Tillaart
// PURPOSE: performance measurement functions
// URL: https://github.com/RobTillaart/SparseMatrix
#include "SparseMatrix.h"
@ -19,6 +19,8 @@ void setup()
Serial.println();
Serial.println(__FILE__);
Serial.println();
Serial.println(SPARSEMATRIX_LIB_VERSION);
Serial.println(sm.size());
Serial.println(sm.count());
Serial.println();

View File

@ -16,5 +16,5 @@ add KEYWORD2
# Constants (LITERAL1)
SPARSEMATRIX_LIB_VERSION LITERAL1
SPARSEMATRIX_MAX_SIZE LITERAL1

View File

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

View File

@ -1,5 +1,5 @@
name=SparseMatrix
version=0.1.1
version=0.1.2
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for sparse matrices.

View File

@ -38,11 +38,20 @@ unittest_teardown()
}
unittest(test_constants)
{
assertEqual(1000, SPARSEMATRIX_MAX_SIZE);
}
unittest(test_constructor)
{
SparseMatrix sm(10);
assertEqual(10, sm.size());
assertEqual(0, sm.count());
SparseMatrix sm2(1100);
assertEqual(1000, sm2.size());
}
@ -57,7 +66,7 @@ unittest(test_set)
assertTrue(sm.set(3, 4, 5));
assertFalse(sm.set(5, 4, 5)); // don't fit any more...
// do not set new element to zero
// do not set new element to zero
sm.clear();
assertEqual(0, sm.count());