diff --git a/.clangd b/.clangd new file mode 100644 index 0000000..359a391 --- /dev/null +++ b/.clangd @@ -0,0 +1,2 @@ +CompileFlags: + Add: [-std=c++20] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..496ee2c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ac1ecbc --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ + +# Recursive wildcard function (properly defined) +rwildcard = $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d)) + +CXX = g++ +CXXFLAGS = -Wall -std=c++20 + +# Use $(call ...) not ${call ...} +ALL_LIBS = $(call rwildcard,math/,*.cpp) $(call rwildcard,generators/,*.cpp) $(call rwildcard,randomness_tests/,*.cpp) + +# Expand wildcard properly for current directory +SRCS = main.cpp $(ALL_LIBS) + +TEST_SRCS = code_tests/test.cpp $(ALL_LIBS) + +TARGET = splat +TEST_TARGET = splat_test + +.PHONY: all main test clean +all: $(TARGET) ${TEST_TARGET} +$(TARGET): $(SRCS) + $(CXX) $(CXXFLAGS) -o $@ $^ + +test: $(TEST_TARGET) + +$(TEST_TARGET): $(TEST_SRCS) + $(CXX) $(CXXFLAGS) -o $@ $^ + +clean: + rm -f $(TARGET) $(TEST_TARGET) *.o + diff --git a/a.out b/a.out index 81fc671..3e28a86 100755 Binary files a/a.out and b/a.out differ diff --git a/code_tests/test.cpp b/code_tests/test.cpp index 33fbb47..d5b620e 100644 --- a/code_tests/test.cpp +++ b/code_tests/test.cpp @@ -1,7 +1,9 @@ #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN #include "./doctest.h" -#include "../math/incomplete_gamma.cpp" +#include "../math/incomplete_gamma.h" +#include "../math/matrix.h" +#include TEST_CASE("igam function"){ @@ -12,6 +14,7 @@ TEST_CASE("igam function"){ // for ii in range(20): // print(f"igamtest({i/2}, {ii/2}, {scipy.special.gammainc(i/2,ii/2)});") + std::cout << "🫟 Splat CodeTests\n"; auto igamtest = [](double a, double x, double req) { REQUIRE(igam(a,x)== doctest::Approx(req).epsilon(0.00000000000001)); @@ -198,4 +201,22 @@ TEST_CASE("igam function"){ igamtest(4.5, 9.0, 0.9648264605330151); igamtest(4.5, 9.5, 0.974807104918331); } -} \ No newline at end of file +} +TEST_CASE("Matrix utilities"){ + splat::matrix<3> testMatrix = { + std::bitset<3>("010"), + std::bitset<3>("110"), + std::bitset<3>("010") + }; + + splat::matrix<3> testMatrix2 = { + std::bitset<3>("010"), + std::bitset<3>("101"), + std::bitset<3>("011") + }; + + + REQUIRE(splat::getRank(testMatrix) == 2); + REQUIRE(splat::getRank(testMatrix2) == 3); + +} diff --git a/codetest.sh b/codetest.sh index 2d812ae..5e0cb1e 100755 --- a/codetest.sh +++ b/codetest.sh @@ -1,3 +1,4 @@ -g++ -std=c++11 code_tests/test.cpp -o testcode.o +g++ -std=c++11 math/matrix.cpp code_tests/test.cpp -o testcode.o ./testcode.o -rm testcode.o \ No newline at end of file +rm testcode.o + diff --git a/generators/LCG/lehmer.cpp b/generators/LCG/lehmer.cpp index 25c94ff..f0d67f6 100644 --- a/generators/LCG/lehmer.cpp +++ b/generators/LCG/lehmer.cpp @@ -7,25 +7,22 @@ #include "../../rng.h" #include "../generator.h" +#include "./lehmer.h" // parameters recommended by Nakazawa & Nakazawa // https://en.wikipedia.org/wiki/Lehmer_random_number_generator namespace splat { - class lehmer_generator : public PRNG { - public: - lehmer_generator(uint32_t genSeed) : PRNG(genSeed) { - seed = genSeed; - } - uint32_t generate() override { - seed = (a * seed) % m; - return seed; - } - std::string getName() override { - return "lehmer"; - } - private: - uint64_t a = 7759097958782935LL; - uint64_t m = 18055400005099021LL; - }; -} \ No newline at end of file + lehmer_generator::lehmer_generator(uint32_t genSeed) : PRNG(genSeed) { + seed = genSeed; + } + + uint32_t lehmer_generator::generate() { + seed = (a * seed) % m; + return seed; + } + + std::string lehmer_generator::getName() { + return "lehmer"; + } +} diff --git a/generators/LCG/lehmer.h b/generators/LCG/lehmer.h new file mode 100644 index 0000000..ed82f72 --- /dev/null +++ b/generators/LCG/lehmer.h @@ -0,0 +1,16 @@ + +#pragma once +#include "../generator.h" +#include + +namespace splat { + class lehmer_generator : public PRNG { + public: + lehmer_generator(uint32_t genSeed); + uint32_t generate() override; + std::string getName() override; + private: + static const uint64_t a = 7759097958782935LL; + static const uint64_t m = 18055400005099021LL; + }; +} diff --git a/generators/generator.h b/generators/generator.h index 11d598d..a1789a9 100644 --- a/generators/generator.h +++ b/generators/generator.h @@ -1,7 +1,9 @@ -#include "../rng.h" #pragma once +#include "../rng.h" + + namespace splat { class PRNG { public: diff --git a/generators/mt19937.cpp b/generators/mt19937.cpp index 082b588..b2eaea7 100644 --- a/generators/mt19937.cpp +++ b/generators/mt19937.cpp @@ -89,38 +89,8 @@ namespace splat { } std::string mt19937_generator::getName() { - return "mt19937-32 test"; + return "mt19937-32"; } } -// namespace splat { -// class mt19937_generator : public PRNG { -// public: -// mt19937_generator(uint32_t genSeed) : PRNG(genSeed) { -// state = mt19937_init(seed); -// nextblock(); -// } -// uint32_t generate() override { -// uint32_t generated = random_values[position]; -// position++; -// if(position>=624){ -// nextblock(); -// } -// return generated; -// } -// std::string getName() override { -// return "mt19937-32"; -// } -// private: -// std::array state; -// std::array random_values; -// int position; -// // goes to next block of 624 values -// void nextblock() { -// state = mt19937_twist(state); -// random_values = mt19937_temper(state); -// position = 0; -// } -// }; -// } \ No newline at end of file diff --git a/generators/xorshift.cpp b/generators/xorshift.cpp index 904e03c..daf017b 100644 --- a/generators/xorshift.cpp +++ b/generators/xorshift.cpp @@ -1,25 +1,22 @@ #include "../rng.h" #include "./generator.h" - +#include +#include "./xorshift.h" // parameters recommended by Nakazawa & Nakazawa // https://en.wikipedia.org/wiki/Lehmer_random_number_generator namespace splat { - class xorshift32 : public PRNG { - public: - xorshift32(uint32_t genSeed) : PRNG(genSeed) { - state = genSeed; - } - uint32_t generate() override { - state ^= state << 13; - state ^= state >> 17; - state ^= state << 5; - return state; - } - std::string getName() override { - return "xorshift32"; - } - private: - uint32_t state; - }; -} \ No newline at end of file + + xorshift32_generator::xorshift32_generator(uint32_t genSeed) : PRNG(genSeed) { + state = genSeed; + } + u_int32_t xorshift32_generator::generate() { + state ^= state << 13; + state ^= state >> 17; + state ^= state << 5; + return state; + } + std::string xorshift32_generator::getName() { + return "xorshift32"; + } +} diff --git a/generators/xorshift.h b/generators/xorshift.h new file mode 100644 index 0000000..ef58635 --- /dev/null +++ b/generators/xorshift.h @@ -0,0 +1,14 @@ + +#pragma once +#include "generator.h" + +namespace splat { + class xorshift32_generator : public PRNG { + public: + xorshift32_generator(uint32_t genSeed); + uint32_t generate() override; + std::string getName() override; + private: + uint32_t state; + }; +} diff --git a/main.cpp b/main.cpp index 24904b5..5b0bc1f 100644 --- a/main.cpp +++ b/main.cpp @@ -6,13 +6,13 @@ // #include "rng.h" -#include "generators/LCG/lehmer.cpp" -#include "generators/mt19937.cpp" -#include "generators/xorshift.cpp" -#include "randomness_tests/frequency_monobit.cpp" -#include "randomness_tests/frequency_block.cpp" -#include "randomness_tests/runs.cpp" -#include "randomness_tests/runs_ones.cpp" +#include "generators/LCG/lehmer.h" +#include "generators/mt19937.h" +#include "generators/xorshift.h" +#include "randomness_tests/frequency_monobit.h" +#include "randomness_tests/frequency_block.h" +#include "randomness_tests/runs.h" +#include "randomness_tests/runs_ones.h" @@ -31,7 +31,7 @@ namespace splat { // add generators here addGen(generators, seed); addGen(generators, seed); - addGen(generators,seed); + addGen(generators,seed); return generators; } diff --git a/main.o b/main.o deleted file mode 100755 index e7aef39..0000000 Binary files a/main.o and /dev/null differ diff --git a/math/incomplete_gamma.cpp b/math/incomplete_gamma.cpp index 517cfeb..5adb8cd 100644 --- a/math/incomplete_gamma.cpp +++ b/math/incomplete_gamma.cpp @@ -1,6 +1,5 @@ #include "../rng.h" - -#pragma once +#include "./incomplete_gamma.h" double igam(double a, double x) { double maxlog = 7.09782712893383996732E2; diff --git a/math/incomplete_gamma.h b/math/incomplete_gamma.h new file mode 100644 index 0000000..55a8ab9 --- /dev/null +++ b/math/incomplete_gamma.h @@ -0,0 +1,4 @@ +#pragma once + +double igam(double a, double x); +double igamc(double a, double x); diff --git a/math/matrix.cpp b/math/matrix.cpp new file mode 100644 index 0000000..324171a --- /dev/null +++ b/math/matrix.cpp @@ -0,0 +1,87 @@ +#include +#include +#include +#include "matrix.h" + +namespace splat { + template + std::bitset& matrix::operator[](int i){ + return bits[i]; + } + + template + const std::bitset& matrix::operator[](int i) const { + return bits[i]; + } + + + template + const bool matrix::get(int row, int column) const { + return bits[row][S-column-1]; + } + + + template + void matrix::debug() { + for(int i=0; i + void gaussianElimination(matrix& matrix){ + int top = 0; + for(int column=0; column temp = matrix[top]; + matrix[top] = matrix[firstOnePosition]; + matrix[firstOnePosition] = temp; + } + + // now we XOR all the rows below our pivot with the pivot row + for(int row = firstOnePosition+1; row + int getRank(matrix& matrix){ + gaussianElimination(matrix); + int rank = 0; + for(int i=0; i(0)){ + rank++; + } + } + return rank; + } + + + + template int getRank<3>(matrix<3>&); + template int getRank<32>(matrix<32>&); +} diff --git a/math/matrix.h b/math/matrix.h new file mode 100644 index 0000000..108dea4 --- /dev/null +++ b/math/matrix.h @@ -0,0 +1,28 @@ + +#pragma once +#include +#include +#include + + + +namespace splat { + template + struct matrix { + std::bitset bits[S]; + std::bitset& operator[](int i); + + const std::bitset& operator[](int i) const; + + const bool get(int row, int column) const; + + void debug(); + }; + + template + void gaussianElimination(matrix& matrix); + + template + int getRank(matrix& matrix); +} + diff --git a/randomness_tests/binary_matrix.cpp b/randomness_tests/binary_matrix.cpp new file mode 100644 index 0000000..c24b101 --- /dev/null +++ b/randomness_tests/binary_matrix.cpp @@ -0,0 +1,21 @@ +#include "./binary_matrix.h" +#include "./rngtest.h" + + +namespace splat { + + binary_matrix_test::binary_matrix_test(std::vector> &testData) : RNGTEST(testData){ + testPValue = runTest(data); + testPassed = testPValue > 0.01; + } + + std::string binary_matrix_test::getName() { + return "Binary Matrix Rank Test"; + } + + // We will use matrices of size 32x32 as recommended + double binary_matrix_test::runTest(std::vector> &data) { + int num_matrices = data.size() / 32; + + } +} diff --git a/randomness_tests/binary_matrix.h b/randomness_tests/binary_matrix.h new file mode 100644 index 0000000..c86a1d2 --- /dev/null +++ b/randomness_tests/binary_matrix.h @@ -0,0 +1,19 @@ + +#pragma once + +#include "../rng.h" +#include "./rngtest.h" +#include "../math/incomplete_gamma.h" +#include "../math/matrix.h" + + + +namespace splat { + + class binary_matrix_test : public RNGTEST { + public: + binary_matrix_test(std::vector> &testData); + std::string getName() override; + double runTest(std::vector> &data) override; + }; +} diff --git a/randomness_tests/frequency_block.cpp b/randomness_tests/frequency_block.cpp index ffab45e..f3e67a4 100644 --- a/randomness_tests/frequency_block.cpp +++ b/randomness_tests/frequency_block.cpp @@ -6,52 +6,46 @@ // #include "../rng.h" -#include "../math/incomplete_gamma.cpp" - +#include "../math/incomplete_gamma.h" +#include "./frequency_block.h" #include "./rngtest.h" namespace splat { - class frequency_block_test : public RNGTEST { - public: - frequency_block_test(std::vector> &testData) : RNGTEST(testData) { - block_size = data.size() * 32 / 150; - testPValue = runTest(data); - testPassed = testPValue > 0.01; - } - std::string getName() override { - return std::format("Frequency Block [{}]", block_size); - } - double runTest(std::vector> &data) override { - // std::cout << "DEBUG: "<> &testData) : RNGTEST(testData) { + block_size = data.size() * 32 / 150; + testPValue = runTest(data); + testPassed = testPValue > 0.01; + } - long long bitcount = data.size() * 32; - long long chunks = bitcount / block_size; + double frequency_block_test::runTest(std::vector> &data) { - double x2stat = 0; - - for(int chunkIndex = 0; chunkIndex < chunks; chunkIndex++){ - // std::cout << "NEWCHUNK: "; - double onecount = 0; - for(int i=0; i> &testData); + std::string getName() override; + double runTest(std::vector> &data) override; + private: + long long block_size; + + }; +} diff --git a/randomness_tests/frequency_monobit.cpp b/randomness_tests/frequency_monobit.cpp index 7b6d59e..138325e 100644 --- a/randomness_tests/frequency_monobit.cpp +++ b/randomness_tests/frequency_monobit.cpp @@ -7,27 +7,26 @@ #include "../rng.h" #include "./rngtest.h" +#include "./frequency_monobit.h" namespace splat { - class frequency_monobit_test : public RNGTEST { - public: - frequency_monobit_test(std::vector> &testData) : RNGTEST(testData) { - testPValue = runTest(data); - testPassed = testPValue > 0.01; - } - std::string getName() override { - return "Frequency Monobit"; - } - double runTest(std::vector> &data) override { - long long s = 0; - for(auto bitset : data){ - for(int i=0; i<32; i++){ - s += (2*bitset[i])-1; - } - } - double sobs = ((double)std::abs(s))/std::sqrt(data.size()*32); - double pvalue = std::erfc(sobs/std::sqrt(2)); - return pvalue; - } - }; -} \ No newline at end of file + frequency_monobit_test::frequency_monobit_test(std::vector> &testData) : RNGTEST(testData) { + testPValue = runTest(data); + testPassed = testPValue > 0.01; + } + + double frequency_monobit_test::runTest(std::vector> &data) { + long long s = 0; + for(auto bitset : data){ + for(int i=0; i<32; i++){ + s += (2*bitset[i])-1; + } + } + double sobs = ((double)std::abs(s))/std::sqrt(data.size()*32); + double pvalue = std::erfc(sobs/std::sqrt(2)); + return pvalue; + } + std::string frequency_monobit_test::getName() { + return "Frequency Monobit"; + } +} diff --git a/randomness_tests/frequency_monobit.h b/randomness_tests/frequency_monobit.h new file mode 100644 index 0000000..6e92d76 --- /dev/null +++ b/randomness_tests/frequency_monobit.h @@ -0,0 +1,22 @@ + +#pragma once +// +// frequency_monobit.cpp +// rng +// +// Created by Asher Falcon on 21/06/2025. +// + +#include "../rng.h" +#include "./rngtest.h" + + + +namespace splat { + class frequency_monobit_test : public RNGTEST { + public: + frequency_monobit_test(std::vector> &testData); + std::string getName() override; + double runTest(std::vector> &data) override; + }; +} diff --git a/randomness_tests/rngtest.h b/randomness_tests/rngtest.h index ad2ffa7..e8e3d61 100644 --- a/randomness_tests/rngtest.h +++ b/randomness_tests/rngtest.h @@ -1,7 +1,10 @@ -#include "../rng.h" #pragma once +#include "../rng.h" + + + namespace splat { class RNGTEST { public: diff --git a/randomness_tests/runs.cpp b/randomness_tests/runs.cpp index 20186d4..3c06f84 100644 --- a/randomness_tests/runs.cpp +++ b/randomness_tests/runs.cpp @@ -1,38 +1,38 @@ #include "../rng.h" #include "./rngtest.h" +#include "./runs.h" namespace splat { - class runs_test : public RNGTEST { - public: - runs_test(std::vector> &testData) : RNGTEST(testData) { - testPValue = runTest(data); - testPassed = testPValue > 0.01; - } - std::string getName() override { - return "Runs"; - } - double runTest(std::vector> &data) override { - long long totalSize = data.size() * 32; - double vnobs = 1; + runs_test::runs_test(std::vector> &testData) : RNGTEST(testData) { + testPValue = runTest(data); + testPassed = testPValue > 0.01; + } + std::string runs_test::getName(){ + return "Runs"; - double onesproportion = 0; + } + double runs_test::runTest(std::vector> &data) { + long long totalSize = data.size() * 32; - for(int i=0; i> &testData); + std::string getName() override; + double runTest(std::vector> &data) override; + }; +} diff --git a/randomness_tests/runs_ones.cpp b/randomness_tests/runs_ones.cpp index 2d75a16..21036fa 100644 --- a/randomness_tests/runs_ones.cpp +++ b/randomness_tests/runs_ones.cpp @@ -1,78 +1,76 @@ #include "../rng.h" #include "./rngtest.h" -#include "../math/incomplete_gamma.cpp" -#define vecdebug(list) for(auto vecdebugitem : list){ std::cout << vecdebugitem <<","; }std::cout << "\n"; - +#include "../math/incomplete_gamma.h" +#include "./runs_ones.h" namespace splat { - class runs_ones_test : public RNGTEST { - public: - runs_ones_test(std::vector> &testData) : RNGTEST(testData) { - testPValue = runTest(data); - testPassed = testPValue > 0.01; - } - std::string getName() override { - return "Runs of 1s"; - } - double runTest(std::vector> &data) override { - long long totalSize = data.size() * 32; - if(totalSize < 750000){ - std::cout << "Error, runs of ones test requires more than 750K bits of input\n"; - return 0; + runs_ones_test::runs_ones_test(std::vector> &testData) : RNGTEST(testData) { + testPValue = runTest(data); + testPassed = testPValue > 0.01; + } + std::string runs_ones_test::getName(){ + return "Runs of 1s"; + } + + double runs_ones_test::runTest(std::vector> &data) { + long long totalSize = data.size() * 32; + + if(totalSize < 750000){ + std::cout << "Error, runs of ones test requires more than 750K bits of input\n"; + return 0; + } + // we do it with M=10^4 here + + std::vector counts(7,0); + + double chunks = totalSize / 10000; + + for(int chunkIndex=0; chunkIndexlongestRun) longestRun = ones; + ones = 0; } - // we do it with M=10^4 here - - std::vector counts(7,0); - - double chunks = totalSize / 10000; - - for(int chunkIndex=0; chunkIndexlongestRun) longestRun = ones; - ones = 0; - } - } - - if(longestRun <=10){ - counts[0]++; - }else if(longestRun>=16){ - counts[6]++; - }else{ - counts[longestRun-10]++; - } - } - - double x2 = 0; - - std::vector probabilities = { - 0.0882, - 0.2092, - 0.2483, - 0.1933, - 0.1208, - 0.0675, - 0.0727 - }; - - for(int i=0; i<7; i++){ - x2 += std::pow((counts[i] - (chunks * probabilities[i])),2.0) /(chunks * probabilities[i]); - - } - return igamc(3, x2/2.0); } - }; -} \ No newline at end of file + + if(longestRun <=10){ + counts[0]++; + }else if(longestRun>=16){ + counts[6]++; + }else{ + counts[longestRun-10]++; + } + + } + double x2 = 0; + + std::vector probabilities = { + 0.0882, + 0.2092, + 0.2483, + 0.1933, + 0.1208, + 0.0675, + 0.0727 + }; + + for(int i=0; i<7; i++){ + x2 += std::pow((counts[i] - (chunks * probabilities[i])),2.0) /(chunks * probabilities[i]); + + } + return igamc(3, x2/2.0); + } +} diff --git a/randomness_tests/runs_ones.h b/randomness_tests/runs_ones.h new file mode 100644 index 0000000..b45549e --- /dev/null +++ b/randomness_tests/runs_ones.h @@ -0,0 +1,15 @@ + +#pragma once +#include "../rng.h" +#include "./rngtest.h" + + +namespace splat { + + class runs_ones_test : public RNGTEST { + public: + runs_ones_test(std::vector> &testData); + std::string getName() override; + double runTest(std::vector> &data) override; + }; +} diff --git a/splat b/splat new file mode 100755 index 0000000..452242f Binary files /dev/null and b/splat differ diff --git a/splat_test b/splat_test new file mode 100755 index 0000000..1eb1929 Binary files /dev/null and b/splat_test differ diff --git a/web/README.md b/web/README.md index 7059a96..7c0e018 100644 --- a/web/README.md +++ b/web/README.md @@ -1,12 +1 @@ -# React + Vite - -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. - -Currently, two official plugins are available: - -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh - -## Expanding the ESLint configuration - -If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project. +This is a web showcase of the 🫟 Splat library, using emscripten to compile the cpp to webassembly in the 'build_wasm.sh' script \ No newline at end of file diff --git a/web/src/App.jsx b/web/src/App.jsx index b693b3f..d3739e1 100644 --- a/web/src/App.jsx +++ b/web/src/App.jsx @@ -7,6 +7,27 @@ function App() { const [randomNum, setRandomNum] = useState(null); const [rng, setRng] = useState(null) + const [nums, setNums] = useState(null); + const [matrixRows, setMatrixRows] = useState(null) + const max = (2**32)-1; + + const rows = 500; + const cols = 500; + + const newNums = () => { + + const newMatrixRows = [] + for(let i=0; i { createModule().then((module) => { setRng(new module.mt19937(5489)) @@ -31,15 +52,39 @@ function App() { Loading... ) : ( +
-
- {randomNum ? randomNum : "Generate a number below"} -
-
- -
+ + {matrixRows ?( +
+ {matrixRows.map((row) => { + return ( +
+ { + row.map((item) => { + return ( +
+ ) + }) + } +
+ ) + })} +
+ ) : ( + Loading... + ) + + }
+
+ )} + )