diff --git a/libraries/SparseMatrix/.arduino-ci.yml b/libraries/SparseMatrix/.arduino-ci.yml index 3115dcd5..1fd3a202 100644 --- a/libraries/SparseMatrix/.arduino-ci.yml +++ b/libraries/SparseMatrix/.arduino-ci.yml @@ -8,4 +8,6 @@ compile: - m4 - esp32 - esp8266 - # - mega2560 \ No newline at end of file + # - mega2560 + libraries: + - "SHT85" \ No newline at end of file diff --git a/libraries/SparseMatrix/README.md b/libraries/SparseMatrix/README.md index 39e351f0..f004d3d6 100644 --- a/libraries/SparseMatrix/README.md +++ b/libraries/SparseMatrix/README.md @@ -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 diff --git a/libraries/SparseMatrix/SparseMatrix.cpp b/libraries/SparseMatrix/SparseMatrix.cpp index 64a0380e..17179252 100644 --- a/libraries/SparseMatrix/SparseMatrix.cpp +++ b/libraries/SparseMatrix/SparseMatrix.cpp @@ -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 -- + diff --git a/libraries/SparseMatrix/SparseMatrix.h b/libraries/SparseMatrix/SparseMatrix.h index 0dd49a71..b2e61b87 100644 --- a/libraries/SparseMatrix/SparseMatrix.h +++ b/libraries/SparseMatrix/SparseMatrix.h @@ -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); }; diff --git a/libraries/SparseMatrix/examples/sparse_matrix_2D_histogram/sparse_matrix_2D_histogram.ino b/libraries/SparseMatrix/examples/sparse_matrix_2D_histogram/sparse_matrix_2D_histogram.ino new file mode 100644 index 00000000..835c62b7 --- /dev/null +++ b/libraries/SparseMatrix/examples/sparse_matrix_2D_histogram/sparse_matrix_2D_histogram.ino @@ -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 -- diff --git a/libraries/SparseMatrix/examples/sparse_matrix_demo/sparse_matrix_demo.ino b/libraries/SparseMatrix/examples/sparse_matrix_demo/sparse_matrix_demo.ino index 5faf5762..dc710f5d 100644 --- a/libraries/SparseMatrix/examples/sparse_matrix_demo/sparse_matrix_demo.ino +++ b/libraries/SparseMatrix/examples/sparse_matrix_demo/sparse_matrix_demo.ino @@ -2,6 +2,7 @@ // FILE: sparse_matrix_demo.ino // AUTHOR: Rob Tillaart // PURPOSE: demo +// URL: https://github.com/RobTillaart/SparseMatrix #include "SparseMatrix.h" diff --git a/libraries/SparseMatrix/examples/sparse_matrix_max/sparse_matrix_max.ino b/libraries/SparseMatrix/examples/sparse_matrix_max/sparse_matrix_max.ino index aee624d8..3e4478df 100644 --- a/libraries/SparseMatrix/examples/sparse_matrix_max/sparse_matrix_max.ino +++ b/libraries/SparseMatrix/examples/sparse_matrix_max/sparse_matrix_max.ino @@ -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" diff --git a/libraries/SparseMatrix/examples/sparse_matrix_performance/performance_0.1.2.txt b/libraries/SparseMatrix/examples/sparse_matrix_performance/performance_0.1.2.txt new file mode 100644 index 00000000..2f93c0ad --- /dev/null +++ b/libraries/SparseMatrix/examples/sparse_matrix_performance/performance_0.1.2.txt @@ -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 + diff --git a/libraries/SparseMatrix/examples/sparse_matrix_performance/sparse_matrix_performance.ino b/libraries/SparseMatrix/examples/sparse_matrix_performance/sparse_matrix_performance.ino index 2aed2836..e8175948 100644 --- a/libraries/SparseMatrix/examples/sparse_matrix_performance/sparse_matrix_performance.ino +++ b/libraries/SparseMatrix/examples/sparse_matrix_performance/sparse_matrix_performance.ino @@ -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(); diff --git a/libraries/SparseMatrix/keywords.txt b/libraries/SparseMatrix/keywords.txt index 9f861009..8cd53218 100644 --- a/libraries/SparseMatrix/keywords.txt +++ b/libraries/SparseMatrix/keywords.txt @@ -16,5 +16,5 @@ add KEYWORD2 # Constants (LITERAL1) SPARSEMATRIX_LIB_VERSION LITERAL1 - +SPARSEMATRIX_MAX_SIZE LITERAL1 diff --git a/libraries/SparseMatrix/library.json b/libraries/SparseMatrix/library.json index 007fd58a..4b503d4a 100644 --- a/libraries/SparseMatrix/library.json +++ b/libraries/SparseMatrix/library.json @@ -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": "*", diff --git a/libraries/SparseMatrix/library.properties b/libraries/SparseMatrix/library.properties index 65d3f0fb..4096cf64 100644 --- a/libraries/SparseMatrix/library.properties +++ b/libraries/SparseMatrix/library.properties @@ -1,5 +1,5 @@ name=SparseMatrix -version=0.1.1 +version=0.1.2 author=Rob Tillaart maintainer=Rob Tillaart sentence=Arduino library for sparse matrices. diff --git a/libraries/SparseMatrix/test/unit_test_001.cpp b/libraries/SparseMatrix/test/unit_test_001.cpp index 6157762b..b5e3f9de 100644 --- a/libraries/SparseMatrix/test/unit_test_001.cpp +++ b/libraries/SparseMatrix/test/unit_test_001.cpp @@ -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());