diff --git a/CHANGELOG.md b/CHANGELOG.md index 790ac39..53a3189 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ - `Distinct` (`rules.h`): no layer twice in one composition, checked on exact types at instantiation (packs, aliases, equal types spelled differently, types from other headers). Named compositions (anything with `::Types`) are spliced recursively; closed operands are also compared by `is_base_of`. Covered in `tests/compile_tests.cpp`. Used by the `.RnD/openDerivation` translator in every composed struct. -- Example `examples/static_net`: static networks (a typelist of parts wired by index, id or query, no runtime data), tinyML on an 8-bit AVR as the running example, with checks, timing +- Example `examples/static_net`: static networks (a typelist of parts wired by index, id or query; the values a net reads are the slots of a state, `hapi/slots.h`, and a register is a layer of it), tinyML on an 8-bit AVR as the running example, with checks, timing (simavr, confirmed on a real chip), and a comparison against a table loop and against emlearn. Uses `Expand` and `Drop`; GCC/Clang only, not built by CI. ## 0.7.0 diff --git a/README.md b/README.md index f2e0114..5ce77de 100644 --- a/README.md +++ b/README.md @@ -601,7 +601,7 @@ confirmed by eye. [`examples/static_net`](examples/static_net) is a different kind of composition: **static networks**, dry, typed, zero-runtime descriptions of dataflow nets (a typelist of parts, wired by index, id or query; -no runtime data but the input view), with tinyML as the running example: a 4-input classifier in 44 B and +the values a net reads are the slots of a state, `hapi/slots.h`, and a register is a layer of it), with tinyML as the running example: a 4-input classifier in 44 B and 25 cycles on an 8-bit ATmega328p. It is measured against a table loop and against emlearn on the same folds, in one build setup; the cycle counts come from simavr and were confirmed on a real Arduino Nano (100 numbers, no difference), and the realization of a cell (unrolled or as a table and a loop) is a diff --git a/examples/static_net/README.md b/examples/static_net/README.md index 9975a66..62fa9b5 100644 --- a/examples/static_net/README.md +++ b/examples/static_net/README.md @@ -2,21 +2,23 @@ Static networks: dry, typed descriptions of dataflow nets. -A **net** is a typelist of parts, wired by index, by id or by a query. It carries no data of its own; the only runtime state is the input view it is evaluated on. +A **net** is a typelist of parts, wired by index, by id or by a query. It carries no data of its own: the values it reads live in a **state** of tag-addressed slots (`hapi::Slot`, see HAPI's README), and the net is evaluated over that state. Because the whole structure is a type, the compiler resolves it at compile time: the forms below compile to the same disassembly as the hand-written equivalents (*What the composition costs*). The running example is a 4-input classifier on an 8-bit AVR: 44 B and 25 cycles on an ATmega328p. -Parts agree on a small **contract** (a static, pure `proc(in)`, optionally `update(in)`); they do not inherit from a framework, and HAPI's `Chain<>` / `APIOf<>` / `Expand<>` do the +Parts agree on a small **contract** (a static, pure `proc(in)`); they do not inherit from a framework, and HAPI's `Chain<>` / `APIOf<>` / `Expand<>` do the composing. Neural-net cells are the running example, not the point: any static dataflow of pure stages fits (a filter chain, a control loop, a sensor fusion), and other contracts can sit beside `proc(in)`. Two inference engines are provided as parts, `wave` (no multiplies: shifts, masks and adds) and `lin` (plain integer linear, multiplies by design), and they mix freely in one net. ```cpp -// models/banknote/net.h -- the trained classifier is a TYPE. Its parameters are template arguments: no table, no state, no interpreter. +// models/banknote/net.h -- the trained classifier is a TYPE. Its parameters are template arguments: no table, no interpreter. +// Its four inputs are the four fields of one slot of the state, read by name (Variance is snet::Field). using BanknoteNet = wave::Cell, wave::Wave<1,WAVE_F1_N,WAVE_F1_S,WAVE_F1_P,WAVE_F1_M>, - wave::Wave<2,WAVE_F2_N,WAVE_F2_S,WAVE_F2_P,WAVE_F2_M>, wave::Wave<3,WAVE_F3_N,WAVE_F3_S,WAVE_F3_P,WAVE_F3_M>>; + wave::Wave, wave::Wave, + wave::Wave, wave::Wave>; +BanknoteState features = banknote({variance, skewness, curtosis, entropy}); // the state: four input bytes, the only runtime data bool y = BanknoteNet::proc(features); // a few shifts, masks and adds; 44 B of flash, 25 cycles on an ATmega328p ``` @@ -39,7 +41,7 @@ The headers use GNU attributes (`[[gnu::always_inline]]`) and the timing harness ```cpp // sugar.h: the net as constexpr values whose TYPES are the net (values carry no data). 274 B on an ATmega328p, identical to the same net written by hand. -constexpr auto orr = cell<-1>(sign, w<2>*a, w<2>*b); // a = x<0>, b = x<1>: input slots +constexpr auto orr = cell<-1>(sign, w<2>*a, w<2>*b); // a = x, b = x: fields of the input state (inputs.h) constexpr auto nand = cell< 3>(sign, w<-2>*a, w<-2>*b); constexpr auto xr = cell<-3>(sign, w<2>*ref(orr), w<2>*ref(nand)); // a cell reads another cell, in place, same pass using Net = decltype(net(orr, nand, xr)); // sizeof(Net) == 1 @@ -47,17 +49,19 @@ using Net = decltype(net(orr, nand, xr)); // sizeof( // refid.h: wiring by id or by a query. Cells carry a hapi::Tag; a cell reads another by id, whatever the position and the engine // (RW is wave::WaveOf,..>): here a wave cell XORs a wave cell and a lin cell using ById = snet::Net< - wave::Cell<0, hapi::Tag, wave::Threshold, wave::Wave<0,0,6,0,0xff>, wave::Wave<1,0,6,0,0xff>>, - lin::Cell<-1, hapi::Tag, lin::Sign, lin::In<0,2>, lin::In<1,2>>, + wave::Cell<0, hapi::Tag, wave::Threshold, wave::Wave, wave::Wave>, + lin::Cell<-1, hapi::Tag, lin::Sign, lin::In, lin::In>, wave::Cell<128, hapi::Tag, wave::Threshold, RW, RW>>; // RefId is RefQ>>: any HAPI predicate over a cell's components works, e.g. RefQ> is "the cell that has lin::Sign"; the first match wins ``` -- **A cycle is a compile error**, not a runtime surprise: `snet::Ref: in-place reference must point to a lower net index; a cycle needs a register (Slot + Store)`. +- **A cycle is a compile error**, not a runtime surprise: `snet::Ref: in-place reference must point to a lower net index; a cycle needs a register (a typed layer that evaluates the cell on prev)`. The check is a `static_assert` in the net's own library code (`include/staticNet.h`), not something a user of the net writes or can forget: a net with a combinational cycle cannot be evaluated, `proc` does not compile (`check/cycle_reject_*.cpp` name the net and call `proc`). A reference to a cell that is not in the net says so in words (`no cell in the net matches Q`, `no cell of that type in the net`) (`check/`: `cycle_reject_*`, `refid_missing`, `sugar_missing`). - **The realization is a compile-time choice.** `cell(sign, terms...)` returns the unrolled `lin::Cell` (one inline multiply-add per term) or, from `SUGAR_ROLL_AT` = 6 terms, the same - terms as a table and a loop (`snet::Roll`); the result is identical, the code is not (see *Realizations* below). `SUGAR_ROLL_AT` is a **size policy**, not a fact: set it huge to never roll. + terms as a table and a loop (`snet::Roll`; it applies to terms that read elements of one array field, such as a 60-band input); the result is identical, the code is not (see *Realizations* below). `SUGAR_ROLL_AT` is a **size policy**, not a fact: set it huge to never roll. +- **A value that survives a pass is a register** (`registers.h`): a layer of the state whose step evaluates cells on the previous state and stores the result. Cells stay pure `proc(in)`; two registers that read each other + (`(a,b)' = (b, a+b)`) are right because both new values come from the previous state (`check/registers_check.cpp`; `registers_avr.cpp` is the same step as a hand-indexed array: same size). - Cells of identical type collapse in `ref()` (identical pure cells compute the same value: deduplication, pinned by `check/sugar_twins.cpp`). ## What was measured @@ -141,13 +145,13 @@ The result also depends on `SNET_INLINE` (`[[gnu::always_inline]]`): avr-gcc 7.3 | | | |---|---| -| `include/` | the headers: `staticNet.h` (the net, `Ctx`, `Ref`, `Slot`; namespace `snet`), `waveCell.h`, `linCell.h` (the engines), `refid.h` (wiring by id / query), `sugar.h`, `roll.h` | +| `include/` | the headers: `staticNet.h` (the net, `Ctx`, `Ref`, and the sources `Field` / `Elem` that read a slot of the state; namespace `snet`), `waveCell.h`, `linCell.h` (the engines), `refid.h` (wiring by id / query), `sugar.h`, `roll.h`, `registers.h` (registers as layers of the state), `inputs.h` (stock input states) | | `models/` | the trained cells: `banknote/` (the running example's cell and its 274 held-out rows), `sonar/` (the 60-input cells of 5 folds), `roll60/` (60-term nets for the size and speed comparisons) | | `src/main.cpp` | the running example (host and AVR) | | `check/` | `build.sh` runs everything: host tests (g++, clang++), programs that must not compile, AVR sizes and identical-disassembly checks, the simulated row-by-row check (`bitexact.py`) | | `measure/` | the timing harness (Timer1, UART) and programs: `run.sh` (simavr), `roll_sweep.sh`, `silicon.py` (flash a real ATmega328p and compare with simavr), `silicon_results.md` | | `compare_emlearn/` | the Banknote comparison: `run.sh` builds and measures every model in one setup; `results.md`; generated models, the fold data and the emlearn headers it compiles against (MIT, unchanged) | -| `train/` | how the trained parameters came about, on a PC: `bn2x.c` (masked-wave search and float perceptron per fold, UCI Banknote), `sonar_lin_train.c` + `gen_lin_sonar.py` (Sonar, quantized to int8 constants) | +| `train/` | how the trained parameters came about, on a PC: `bn2x.c` (masked-wave search and float perceptron per fold, UCI Banknote; it writes the features and columns by name), `sonar_lin_train.c` + `gen_lin_sonar.py` (Sonar, quantized to int8 constants) | ## Scope diff --git a/examples/static_net/check/banknote_avr_check.cpp b/examples/static_net/check/banknote_avr_check.cpp index 2a80319..d9d2a5a 100644 --- a/examples/static_net/check/banknote_avr_check.cpp +++ b/examples/static_net/check/banknote_avr_check.cpp @@ -29,10 +29,10 @@ int main(){ uart_init(); uint16_t a=0,c=0; for(uint16_t r=0;r f{{pgm_read_byte(&WAVE_VEC[r][0]),pgm_read_byte(&WAVE_VEC[r][1]), - pgm_read_byte(&WAVE_VEC[r][2]),pgm_read_byte(&WAVE_VEC[r][3])}}; + BanknoteState f=banknote({pgm_read_byte(&WAVE_VEC[r][WAVE_COL_VARIANCE]),pgm_read_byte(&WAVE_VEC[r][WAVE_COL_SKEWNESS]), + pgm_read_byte(&WAVE_VEC[r][WAVE_COL_CURTOSIS]),pgm_read_byte(&WAVE_VEC[r][WAVE_COL_ENTROPY])}); bool o=BanknoteNet::proc(f); - a+=o==pgm_read_byte(&WAVE_VEC[r][5]); c+=o==pgm_read_byte(&WAVE_VEC[r][4]); + a+=o==pgm_read_byte(&WAVE_VEC[r][WAVE_COL_MODEL]); c+=o==pgm_read_byte(&WAVE_VEC[r][WAVE_COL_LABEL]); } agree_=a; correct_=c; for(;;){ diff --git a/examples/static_net/check/banknote_host_check.cpp b/examples/static_net/check/banknote_host_check.cpp index dae23c6..3962052 100644 --- a/examples/static_net/check/banknote_host_check.cpp +++ b/examples/static_net/check/banknote_host_check.cpp @@ -6,9 +6,9 @@ int main(){ int agree=0,correct=0; for(int r=0;r f{{WAVE_VEC[r][0],WAVE_VEC[r][1],WAVE_VEC[r][2],WAVE_VEC[r][3]}}; + BanknoteState f=banknote({WAVE_VEC[r][WAVE_COL_VARIANCE],WAVE_VEC[r][WAVE_COL_SKEWNESS],WAVE_VEC[r][WAVE_COL_CURTOSIS],WAVE_VEC[r][WAVE_COL_ENTROPY]}); bool o=BanknoteNet::proc(f); - agree+=o==WAVE_VEC[r][5]; correct+=o==WAVE_VEC[r][4]; + agree+=o==WAVE_VEC[r][WAVE_COL_MODEL]; correct+=o==WAVE_VEC[r][WAVE_COL_LABEL]; } printf("model agreement %d/%d, accuracy %d/%d\n",agree,WAVE_NVEC,correct,WAVE_NVEC); return agree!=WAVE_NVEC; diff --git a/examples/static_net/check/bench.h b/examples/static_net/check/bench.h index f54147d..2bd2343 100644 --- a/examples/static_net/check/bench.h +++ b/examples/static_net/check/bench.h @@ -13,6 +13,7 @@ #pragma once #include #include "waveCell.h" +#include "inputs.h" // the rows live in RAM/flash as plain data unless the platform says otherwise (AVR: SONAR_LIN_VEC_ATTR PROGMEM and BENCH_VEC with pgm_read_byte) #ifndef SONAR_LIN_VEC_ATTR #define SONAR_LIN_VEC_ATTR @@ -36,13 +37,13 @@ void bench_irq_on(); static inline void bench_start(){ DEMCR|=(1ul<<24); DWT_CYCCNT=0; DWT_CTRL|=1u; } // out of line, so the generated code of each cell can be read from the ELF on its own (arm-none-eabi-objdump -d) -__attribute__((noinline)) bool runNarrow(const wave::Features<60>& f){ return SonarLinFold0::proc(f); } -__attribute__((noinline)) bool runWide (const wave::Features<60>& f){ return SonarLinFold0Wide::proc(f); } +__attribute__((noinline)) bool runNarrow(const inp::Bytes60& f){ return SonarLinFold0::proc(f); } +__attribute__((noinline)) bool runWide (const inp::Bytes60& f){ return SonarLinFold0Wide::proc(f); } -static wave::Features<60> benchRow(uint16_t r){ wave::Features<60> f; for(int j=0;j<60;j++) f.v[j]=BENCH_VEC(r,j); return f; } +static inp::Bytes60 benchRow(uint16_t r){ inp::Bytes60 f; for(int j=0;j<60;j++) inp::band(f)[j]=BENCH_VEC(r,j); return f; } enum { REPS=25 }; -[[maybe_unused]] static uint32_t benchCycles(bool (*fn)(const wave::Features<60>&), const wave::Features<60>& f){ +[[maybe_unused]] static uint32_t benchCycles(bool (*fn)(const inp::Bytes60&), const inp::Bytes60& f){ uint32_t best=0xFFFFFFFFu, all[REPS]; for(int i=0;i f=benchRow(r); - bool truth=BENCH_VEC(r,60), flt=BENCH_VEC(r,61); + inp::Bytes60 f=benchRow(r); + bool truth=BENCH_VEC(r,SONAR_COL_LABEL), flt=BENCH_VEC(r,SONAR_COL_FLOAT); bool n=runNarrow(f), w=runWide(f); okN+=(n==truth); agN+=(n==flt); okW+=(w==truth); agW+=(w==flt); rowsN[r]=n?'1':'0'; rowsW[r]=w?'1':'0'; @@ -77,7 +78,7 @@ static void bench_correctness(){ } static void bench_cycles(){ - wave::Features<60> f=benchRow(0); + inp::Bytes60 f=benchRow(0); bench_str("cycles narrow: "); benchCycles(runNarrow,f); bench_str("\r\n"); bench_str("cycles wide : "); benchCycles(runWide,f); bench_str("\r\n"); } diff --git a/examples/static_net/check/build.sh b/examples/static_net/check/build.sh index 1a0c416..ed74cd5 100755 --- a/examples/static_net/check/build.sh +++ b/examples/static_net/check/build.sh @@ -60,6 +60,8 @@ run sugar_twins sugar_twins.cpp "twins OK" run sugar_roll sugar_roll.cpp "dense 20000/20000, gapped 20000/20000" run roll_host roll_host.cpp "rolled==unrolled 10000/10000, sparse-order rolled==unrolled 10000/10000" run roll_gaps roll_gaps.cpp "gapped rolled==unrolled 20000/20000" +echo "== registers: a value that survives a pass is a typed layer (registers.h), the cells unchanged" +run registers_check registers_check.cpp "0 of 30 passes wrong, output cell wrong 0 times" echo "== the trained models on the host" run banknote_host_check banknote_host_check.cpp "274/274" run sonar_lin_check sonar_lin_check.cpp "agreement 100.00" @@ -80,6 +82,8 @@ avr sugar_roll_avr sugar_roll_avr.cpp "322 B / 62 B" avr sugar_roll_hand_avr sugar_roll_hand_avr.cpp "322 B / 62 B"; same "sugar picks the rolled form a person would write" sugar_roll_avr sugar_roll_hand_avr avr sugar_roll_avr_off sugar_roll_avr.cpp "1006 B / 62 B" -DSUGAR_ROLL_AT=1000 avr sugar_unroll_hand_avr sugar_unroll_hand_avr.cpp "1006 B / 62 B"; same "SUGAR_ROLL_AT huge == the unrolled cell by hand" sugar_roll_avr_off sugar_unroll_hand_avr +avr registers_avr registers_avr.cpp "220 B / 4 B" +avr registers_avr_flat registers_avr.cpp "220 B / 4 B" -DFLAT # the hand-indexed twin that reads before it writes: same size avr banknote_avr_check banknote_avr_check.cpp "2346 B / 26 B" # the Banknote cell on a board: it reports over UART if have simavr && have python3; then echo "== AVR: the same rows through the same function, simulated ATmega328p against the host, row by row" diff --git a/examples/static_net/check/cycle_reject_pair.cpp b/examples/static_net/check/cycle_reject_pair.cpp index 8000647..2e4baf1 100644 --- a/examples/static_net/check/cycle_reject_pair.cpp +++ b/examples/static_net/check/cycle_reject_pair.cpp @@ -1,4 +1,5 @@ #include "waveCell.h" +#include "inputs.h" using namespace wave; using Bad=Net>, Cell<0,RefWave<0,0,0,0,0xff>>>; -int main(){Features<1> f{{0}}; return Bad::proc<1>(f);} +int main(){auto f=inp::one({0}); return Bad::proc<1>(f);} diff --git a/examples/static_net/check/cycle_reject_self.cpp b/examples/static_net/check/cycle_reject_self.cpp index d337542..cc3a1fd 100644 --- a/examples/static_net/check/cycle_reject_self.cpp +++ b/examples/static_net/check/cycle_reject_self.cpp @@ -1,4 +1,5 @@ #include "waveCell.h" +#include "inputs.h" using namespace wave; using Bad=Net>>; -int main(){Features<1> f{{0}}; return Bad::proc<0>(f);} +int main(){auto f=inp::one({0}); return Bad::proc<0>(f);} diff --git a/examples/static_net/check/mixed_avr_size.cpp b/examples/static_net/check/mixed_avr_size.cpp index b92d23b..9fe7a7c 100644 --- a/examples/static_net/check/mixed_avr_size.cpp +++ b/examples/static_net/check/mixed_avr_size.cpp @@ -1,10 +1,11 @@ #include "waveCell.h" +#include "inputs.h" #include "linCell.h" using Mixed=snet::Net< - wave::Cell<0, wave::Threshold, wave::Wave<0,0,6,0,0xff>, wave::Wave<1,0,6,0,0xff>>, - lin::Cell<-1, lin::Sign, lin::In<0,2>, lin::In<1,2>>, + wave::Cell<0, wave::Threshold, wave::Wave, wave::Wave>, + lin::Cell<-1, lin::Sign, lin::In, lin::In>, wave::Cell<128,wave::Threshold, wave::RefWave<0,0,6,0,0xff>, wave::RefWave<1,0,6,0,0xff>>, - lin::Cell<0, lin::RefIn<2,10>, lin::RefIn<0,-3>, lin::In<0,7>> + lin::Cell<0, lin::RefIn<2,10>, lin::RefIn<0,-3>, lin::In> >; volatile uint8_t in_[2]; volatile int16_t out_; -int main(){ for(;;){ wave::Features<2> f{{in_[0],in_[1]}}; out_=Mixed::proc<3>(f);} } +int main(){ for(;;){ auto f=inp::ab({in_[0],in_[1]}); out_=Mixed::proc<3>(f);} } diff --git a/examples/static_net/check/mixed_check.cpp b/examples/static_net/check/mixed_check.cpp index d1171b7..0ffaea9 100644 --- a/examples/static_net/check/mixed_check.cpp +++ b/examples/static_net/check/mixed_check.cpp @@ -1,19 +1,20 @@ // two engines in one static net: wave cells and integer linear cells reference each other in place #include "waveCell.h" +#include "inputs.h" #include "linCell.h" #include using Mixed=snet::Net< - /*0 wave NAND */ wave::Cell<0, wave::Threshold, wave::Wave<0,0,6,0,0xff>, wave::Wave<1,0,6,0,0xff>>, - /*1 lin OR */ lin::Cell<-1, lin::Sign, lin::In<0,2>, lin::In<1,2>>, + /*0 wave NAND */ wave::Cell<0, wave::Threshold, wave::Wave, wave::Wave>, + /*1 lin OR */ lin::Cell<-1, lin::Sign, lin::In, lin::In>, /*2 wave AND(Ref0,Ref1) = XOR */ wave::Cell<128,wave::Threshold, wave::RefWave<0,0,6,0,0xff>, wave::RefWave<1,0,6,0,0xff>>, /*3 lin raw (int16, no readout): 10*xor - 3*nand + 7*a */ - lin::Cell<0, lin::RefIn<2,10>, lin::RefIn<0,-3>, lin::In<0,7>> + lin::Cell<0, lin::RefIn<2,10>, lin::RefIn<0,-3>, lin::In> >; int main(){ int ok=1; for(int a=0;a<2;a++)for(int b=0;b<2;b++){ - wave::Features<2> f{{(wave::u8)a,(wave::u8)b}}; + auto f=inp::ab({uint8_t(a),uint8_t(b)}); int nand=Mixed::proc<0>(f), orr=Mixed::proc<1>(f), x=Mixed::proc<2>(f), r=Mixed::proc<3>(f); int rexp=10*(a^b)-3*!(a&&b)+7*a; printf("a=%d b=%d nand=%d or=%d xor=%d raw=%d (exp %d)\n",a,b,nand,orr,x,r,rexp); diff --git a/examples/static_net/check/net_expand.cpp b/examples/static_net/check/net_expand.cpp index 46c7196..ddddd03 100644 --- a/examples/static_net/check/net_expand.cpp +++ b/examples/static_net/check/net_expand.cpp @@ -4,15 +4,16 @@ // The cells themselves stay whole: a cell is an APIOf, a leaf for queries and Filter/Map (plan D3), so what a walk // sees inside a Net is cells, never a cell's own components. refid keeps FromTypes for exactly that reason. #include "waveCell.h" +#include "inputs.h" #include "linCell.h" #include "refid.h" using namespace hapi; namespace { enum : int { A=1, B=2, C=3 }; - using CellA = wave::Cell<0, Tag, wave::Threshold, wave::Wave<0,0,6,0,0xff>>; - using CellB = lin::Cell<-1, Tag, lin::Sign, lin::In<0,2>>; - using CellC = wave::Cell<128,Tag, wave::Threshold, wave::Wave<1,0,6,0,0xff>>; + using CellA = wave::Cell<0, Tag, wave::Threshold, wave::Wave>; + using CellB = lin::Cell<-1, Tag, lin::Sign, lin::In>; + using CellC = wave::Cell<128,Tag, wave::Threshold, wave::Wave>; using N = snet::Net; using N0 = snet::Net<>; diff --git a/examples/static_net/check/refid_avr.cpp b/examples/static_net/check/refid_avr.cpp index 4c108be..625a7cc 100644 --- a/examples/static_net/check/refid_avr.cpp +++ b/examples/static_net/check/refid_avr.cpp @@ -1,4 +1,5 @@ #include "waveCell.h" +#include "inputs.h" #include "linCell.h" #include "refid.h" @@ -7,11 +8,11 @@ template using RW=wave::WaveOf using RI=lin::Term,w>; // cells in any order the generator likes; wiring by id, not position using ById=snet::Net< - wave::Cell<0, hapi::Tag, wave::Threshold, wave::Wave<0,0,6,0,0xff>, wave::Wave<1,0,6,0,0xff>>, - lin::Cell<-1, hapi::Tag, lin::Sign, lin::In<0,2>, lin::In<1,2>>, + wave::Cell<0, hapi::Tag, wave::Threshold, wave::Wave, wave::Wave>, + lin::Cell<-1, hapi::Tag, lin::Sign, lin::In, lin::In>, wave::Cell<128,hapi::Tag, wave::Threshold, RW, RW>, - lin::Cell<0, hapi::Tag, RI, RI, lin::In<0,7>> + lin::Cell<0, hapi::Tag, RI, RI, lin::In> >; volatile uint8_t in_[2]; volatile int16_t out_; -int main(){ for(;;){ wave::Features<2> f{{in_[0],in_[1]}}; out_=ById::proc<3>(f);} } +int main(){ for(;;){ auto f=inp::ab({in_[0],in_[1]}); out_=ById::proc<3>(f);} } diff --git a/examples/static_net/check/refid_check.cpp b/examples/static_net/check/refid_check.cpp index 6379253..715e921 100644 --- a/examples/static_net/check/refid_check.cpp +++ b/examples/static_net/check/refid_check.cpp @@ -1,4 +1,5 @@ #include "waveCell.h" +#include "inputs.h" #include "linCell.h" #include "refid.h" #include @@ -7,13 +8,13 @@ template using RW=wave::WaveOf using RI=lin::Term,w>; // cells in any order the generator likes; wiring by id, not position using ById=snet::Net< - wave::Cell<0, hapi::Tag, wave::Threshold, wave::Wave<0,0,6,0,0xff>, wave::Wave<1,0,6,0,0xff>>, - lin::Cell<-1, hapi::Tag, lin::Sign, lin::In<0,2>, lin::In<1,2>>, + wave::Cell<0, hapi::Tag, wave::Threshold, wave::Wave, wave::Wave>, + lin::Cell<-1, hapi::Tag, lin::Sign, lin::In, lin::In>, wave::Cell<128,hapi::Tag, wave::Threshold, RW, RW>, - lin::Cell<0, hapi::Tag, RI, RI, lin::In<0,7>> + lin::Cell<0, hapi::Tag, RI, RI, lin::In> >; int main(){ int ok=1; - for(int a=0;a<2;a++)for(int b=0;b<2;b++){ wave::Features<2> f{{(wave::u8)a,(wave::u8)b}}; + for(int a=0;a<2;a++)for(int b=0;b<2;b++){ auto f=inp::ab({uint8_t(a),uint8_t(b)}); int x=ById::proc<2>(f), r=ById::proc<3>(f), rexp=10*(a^b)-3*!(a&&b)+7*a; ok&=x==(a^b)&&r==rexp; } printf("sizeof=%zu %s\n",sizeof(ById),ok?"ALL OK":"FAIL"); return !ok; } diff --git a/examples/static_net/check/refid_cycle.cpp b/examples/static_net/check/refid_cycle.cpp index bf78239..64b235b 100644 --- a/examples/static_net/check/refid_cycle.cpp +++ b/examples/static_net/check/refid_cycle.cpp @@ -1,5 +1,6 @@ #include "waveCell.h" +#include "inputs.h" #include "refid.h" template using RW=wave::WaveOf,n,s,p,m>; using Bad=snet::Net,RW<2,0,0,0,0xff>>, wave::Cell<0,hapi::Tag<2>,RW<1,0,0,0,0xff>>>; -int main(){ wave::Features<1> f{{0}}; return Bad::proc<1>(f); } +int main(){ auto f=inp::one({0}); return Bad::proc<1>(f); } diff --git a/examples/static_net/check/refid_ids.cpp b/examples/static_net/check/refid_ids.cpp index bc16324..8b856dc 100644 --- a/examples/static_net/check/refid_ids.cpp +++ b/examples/static_net/check/refid_ids.cpp @@ -1,13 +1,14 @@ // refid.h: what the lookup sees, compile-only (g++/clang++/avr-g++). The negative case is refid_missing; runtime is refq_check. #include "waveCell.h" +#include "inputs.h" #include "linCell.h" #include "refid.h" using namespace snet; namespace { enum : int { A=10, B=20, C=30, ABSENT=99 }; - using CA=wave::Cell<0, hapi::Tag, wave::Threshold, wave::Wave<0,0,6,0,0xff>>; - using CB=lin::Cell<-1, hapi::Tag, lin::Sign, lin::In<0,2>>; - using CC=wave::Cell<128,hapi::Tag, wave::Threshold, wave::Wave<1,0,6,0,0xff>>; + using CA=wave::Cell<0, hapi::Tag, wave::Threshold, wave::Wave>; + using CB=lin::Cell<-1, hapi::Tag, lin::Sign, lin::In>; + using CC=wave::Cell<128,hapi::Tag, wave::Threshold, wave::Wave>; using N =Net; template using T=hapi::SameAs>; static_assert(std::is_same,hapi::Chain>::value, "the cells come from HAPI's Expand, in order"); diff --git a/examples/static_net/check/refid_missing.cpp b/examples/static_net/check/refid_missing.cpp index ee6c15c..bb7020e 100644 --- a/examples/static_net/check/refid_missing.cpp +++ b/examples/static_net/check/refid_missing.cpp @@ -1,7 +1,8 @@ // EXPECT-ERROR: no cell in the net matches Q // RI<77> names an id no cell carries: one clear message instead of HAPI's internal "no type named 'Result' in FindFirst_<...>". #include "waveCell.h" +#include "inputs.h" #include "refid.h" template using RW=wave::WaveOf,n,s,p,m>; using Bad=snet::Net,RW<77,0,0,0,0xff>>>; -int main(){ wave::Features<1> f{{0}}; return Bad::proc<0>(f); } +int main(){ auto f=inp::one({0}); return Bad::proc<0>(f); } diff --git a/examples/static_net/check/refid_order.cpp b/examples/static_net/check/refid_order.cpp index 122b7d4..05f3288 100644 --- a/examples/static_net/check/refid_order.cpp +++ b/examples/static_net/check/refid_order.cpp @@ -1,6 +1,7 @@ // cells in a different order than refid_check.cpp: ids non-monotonic and out of step with indices, // an unrelated cell first shifts every index, OR sits before NAND -- wiring is by id, not position #include "waveCell.h" +#include "inputs.h" #include "linCell.h" #include "refid.h" #include @@ -8,13 +9,13 @@ enum : int { NAND=99, OR=7, XOR=42, RAW=5, PAD=1 }; template using RW=wave::WaveOf,n,s,p,m>; template using RI=lin::Term,w>; using P=snet::Net< - lin::Cell<5, hapi::Tag, lin::In<0,1>>, // idx0, unrelated - lin::Cell<-1, hapi::Tag, lin::Sign, lin::In<0,2>, lin::In<1,2>>, // idx1 (OR before NAND) - wave::Cell<0, hapi::Tag, wave::Threshold, wave::Wave<0,0,6,0,0xff>, wave::Wave<1,0,6,0,0xff>>, // idx2 + lin::Cell<5, hapi::Tag, lin::In>, // idx0, unrelated + lin::Cell<-1, hapi::Tag, lin::Sign, lin::In, lin::In>, // idx1 (OR before NAND) + wave::Cell<0, hapi::Tag, wave::Threshold, wave::Wave, wave::Wave>, // idx2 wave::Cell<128,hapi::Tag, wave::Threshold, RW, RW>, // idx3 - lin::Cell<0, hapi::Tag, RI, RI, lin::In<0,7>> // idx4 + lin::Cell<0, hapi::Tag, RI, RI, lin::In> // idx4 >; int main(){ int ok=1; - for(int a=0;a<2;a++)for(int b=0;b<2;b++){ wave::Features<2> f{{(wave::u8)a,(wave::u8)b}}; + for(int a=0;a<2;a++)for(int b=0;b<2;b++){ auto f=inp::ab({uint8_t(a),uint8_t(b)}); int x=P::proc<3>(f), r=P::proc<4>(f), rexp=10*(a^b)-3*!(a&&b)+7*a; ok&=x==(a^b)&&r==rexp; } printf("permuted %s\n",ok?"ALL OK":"FAIL"); return !ok; } diff --git a/examples/static_net/check/refq_check.cpp b/examples/static_net/check/refq_check.cpp index 7e64180..0b62755 100644 --- a/examples/static_net/check/refq_check.cpp +++ b/examples/static_net/check/refq_check.cpp @@ -1,5 +1,6 @@ // RefQ at run time: wiring by a criterion, not an index. The last two cases pin what an id is: just a query, first match wins. #include "waveCell.h" +#include "inputs.h" #include "linCell.h" #include "refid.h" #include @@ -9,19 +10,19 @@ template using RI=lin::Term,w>; template using Tag_=hapi::SameAs; // XOR wires NAND by its tag and OR as "the cell that has lin::Sign": a criterion that is not an id using X=snet::Net< - wave::Cell<0, hapi::Tag, wave::Threshold, wave::Wave<0,0,6,0,0xff>, wave::Wave<1,0,6,0,0xff>>, - lin::Cell<-1, hapi::Tag, lin::Sign, lin::In<0,2>, lin::In<1,2>>, + wave::Cell<0, hapi::Tag, wave::Threshold, wave::Wave, wave::Wave>, + lin::Cell<-1, hapi::Tag, lin::Sign, lin::In, lin::In>, wave::Cell<128,hapi::Tag, wave::Threshold, RQ>,0,6,0,0xff>, RQ,0,6,0,0xff>> >; // two cells carry Tag: the first outputs a, the second b. Wiring by that tag gets the FIRST (a), not an error. using Dup=snet::Net< - lin::Cell<0, hapi::Tag, lin::In<0,1>>, - lin::Cell<0, hapi::Tag, lin::In<1,1>>, + lin::Cell<0, hapi::Tag, lin::In>, + lin::Cell<0, hapi::Tag, lin::In>, lin::Cell<0, hapi::Tag, RI> >; static_assert(snet::CellsMatching>,Dup>::size==2,"the net really has two DUP cells"); int main(){ int ok=1; - for(int a=0;a<2;a++)for(int b=0;b<2;b++){ wave::Features<2> f{{(wave::u8)a,(wave::u8)b}}; + for(int a=0;a<2;a++)for(int b=0;b<2;b++){ auto f=inp::ab({uint8_t(a),uint8_t(b)}); ok&=X::proc<2>(f)==(a^b); // criterion-wired XOR ok&=Dup::proc<2>(f)==a; // first match wins: a, whereas the second DUP cell would give b } diff --git a/examples/static_net/check/registers_avr.cpp b/examples/static_net/check/registers_avr.cpp new file mode 100644 index 0000000..4af22dd --- /dev/null +++ b/examples/static_net/check/registers_avr.cpp @@ -0,0 +1,27 @@ +// The Fibonacci registers of registers_check.cpp as a whole AVR program: typed (default) or hand-indexed, one harness. +// -DFLAT hand-indexed, both old values read before either new one is written (what prev/next means): must be the same image +// -DFLAT_NAIVE hand-indexed, the second register read after the first is written (p and n may alias, so the compiler reloads) +#include "waveCell.h" +#include "registers.h" +struct FibTag {}; +struct SlotFib { uint8_t a, b; }; +using FA = snet::Field; using FB = snet::Field; +using FibRegs = snet::Registers>>, + snet::Reg<&SlotFib::b, wave::Cell<0, wave::Wave, wave::Wave>>>; +using FibState = hapi::APIOf>::Res; +volatile uint8_t in_a, in_b, out_a, out_b; +#if defined(FLAT) || defined(FLAT_NAIVE) +struct Flat { uint8_t v[2]; }; // [0] a, [1] b +#ifdef FLAT_NAIVE +extern "C" __attribute__((noinline)) void run_step(const Flat* p, Flat* n) { n->v[0] = p->v[1]; n->v[1] = uint8_t(p->v[0] + p->v[1]); } +#else +extern "C" __attribute__((noinline)) void run_step(const Flat* p, Flat* n) { uint8_t a = p->v[0], b = p->v[1]; n->v[0] = b; n->v[1] = uint8_t(a + b); } +#endif +int main() { Flat p, n; p.v[0] = in_a; p.v[1] = in_b; + for (;;) { run_step(&p, &n); p = n; out_a = p.v[0]; out_b = p.v[1]; } } +#else +extern "C" __attribute__((noinline)) void run_step(const FibState* p, FibState* n) { n->step(*p); } +int main() { FibState p, n; hapi::slot(p).a = in_a; hapi::slot(p).b = in_b; + for (;;) { run_step(&p, &n); p = n; out_a = hapi::slot(p).a; out_b = hapi::slot(p).b; } } +#endif diff --git a/examples/static_net/check/registers_check.cpp b/examples/static_net/check/registers_check.cpp new file mode 100644 index 0000000..7352be4 --- /dev/null +++ b/examples/static_net/check/registers_check.cpp @@ -0,0 +1,40 @@ +// Registers as layers of the state (registers.h) over the cells of a net, which stay `proc(in)`. +// counter one register, n' = n + 1 +// fibonacci two registers that read each other, (a,b)' = (b, a+b): both new values come from the previous state, so the recurrence holds +// output a combinational cell (a Net cell) read over the state after the step +#include "waveCell.h" +#include "linCell.h" +#include "registers.h" +#include + +struct CounterTag {}; +struct SlotCounter { uint8_t n; }; +using N = snet::Field; +using CounterRegs = snet::Registers>>>; // n + 1 +using CounterState = hapi::APIOf>::Res; + + +struct FibTag {}; +struct SlotFib { uint8_t a, b; }; +using FA = snet::Field; using FB = snet::Field; +using FibRegs = snet::Registers>>, // a' = b + snet::Reg<&SlotFib::b, wave::Cell<0, wave::Wave, wave::Wave>>>; // b' = a + b (mod 256, as the u8 engine) +using FibState = hapi::APIOf>::Res; + +// a combinational cell over the registers, read with Net<>::proc on the finished state: is b odd? +using Out = snet::Net>>; + +int main() { + printf("counter:"); CounterState p{}, q{}; hapi::slot(p).n = 0; + for (int i = 0; i < 5; i++) { q.step(p); p = q; printf(" %d", hapi::slot(p).n); } + printf("\n"); + FibState a{}, b{}; hapi::slot(a).a = 0; hapi::slot(a).b = 1; int x = 0, y = 1, bad = 0, badOut = 0; + for (int i = 0; i < 30; i++) { + b.step(a); a = b; int t = (x + y) & 255; x = y; y = t; + bad += hapi::slot(a).a != x || hapi::slot(a).b != y; + badOut += Out::proc<0>(a) != bool(y & 1); // (b<<7)&0x80 plus the bias 128 wraps to 0 when b is odd: Threshold (< 128) reads 1 + } + printf("fibonacci: (a,b)=(%d,%d), %d of 30 passes wrong, output cell wrong %d times\n", hapi::slot(a).a, hapi::slot(a).b, bad, badOut); + return bad || badOut; +} diff --git a/examples/static_net/check/roll_avr.cpp b/examples/static_net/check/roll_avr.cpp index d4d4b8d..7d60295 100644 --- a/examples/static_net/check/roll_avr.cpp +++ b/examples/static_net/check/roll_avr.cpp @@ -4,4 +4,4 @@ volatile uint8_t in_[60]; volatile uint8_t out_; #ifndef USE #define USE Rolled #endif -int main(){ for(;;){ wave::Features<60> f; for(int i=0;i<60;i++) f.v[i]=in_[i]; out_=USE::proc<0>(f);} } +int main(){ for(;;){ inp::Bytes60 f; for(int i=0;i<60;i++) inp::band(f)[i]=in_[i]; out_=USE::proc<0>(f);} } diff --git a/examples/static_net/check/roll_gaps.cpp b/examples/static_net/check/roll_gaps.cpp index 3806eeb..3f71721 100644 --- a/examples/static_net/check/roll_gaps.cpp +++ b/examples/static_net/check/roll_gaps.cpp @@ -7,9 +7,9 @@ using namespace snet; static_assert( IsIota<0>::value && IsIota<0,0>::value && IsIota<0,0,1,2>::value, "0..n-1 in order is dense"); static_assert(!IsIota<0,1,0>::value && !IsIota<0,0,2>::value && !IsIota<0,1,2>::value, "reversed, gapped, or not starting at 0 is not"); -using U = Net,T<4,-90>,T<10,5>,T<11,127>,T<12,-128>,T<30,60>,T<59,-7>,T<5,9>,T<5,-4>,B32<-1500>>>; -using R = Net,T<4,-90>,T<10,5>,T<11,127>,T<12,-128>,T<30,60>,T<59,-7>,T<5,9>,T<5,-4>>,B32<-1500>>>; +using U = Net,17>,T,-90>,T,5>,T,127>,T,-128>,T,60>,T,-7>,T,9>,T,-4>,B32<-1500>>>; +using R = Net,17>,T,-90>,T,5>,T,127>,T,-128>,T,60>,T,-7>,T,9>,T,-4>>,B32<-1500>>>; int main(){ int agree=0, n=20000; srand(11); - for(int t=0;t f; for(int i=0;i<60;i++) f.v[i]=t<2 ? (t?255:0) : rand()&255; // rows 0 and 1: all 0, all 255 + for(int t=0;t(f)==R::proc<0>(f); } printf("gapped rolled==unrolled %d/%d\n",agree,n); return agree!=n; } diff --git a/examples/static_net/check/roll_host.cpp b/examples/static_net/check/roll_host.cpp index 7e2bc15..e6f10a7 100644 --- a/examples/static_net/check/roll_host.cpp +++ b/examples/static_net/check/roll_host.cpp @@ -2,6 +2,6 @@ #include #include int main(){ int agree=0,agreeS=0; srand(3); - for(int t=0;t<10000;t++){ wave::Features<60> f; for(int i=0;i<60;i++) f.v[i]=rand()&255; + for(int t=0;t<10000;t++){ inp::Bytes60 f; for(int i=0;i<60;i++) inp::band(f)[i]=rand()&255; bool u=Unrolled::proc<0>(f), r=Rolled::proc<0>(f), s=Sparse::proc<0>(f); agree+=u==r; agreeS+=u==s; } printf("rolled==unrolled %d/10000, sparse-order rolled==unrolled %d/10000\n",agree,agreeS); } diff --git a/examples/static_net/check/sonar_lin_avr_size.cpp b/examples/static_net/check/sonar_lin_avr_size.cpp index 2908d7f..ebd31d4 100644 --- a/examples/static_net/check/sonar_lin_avr_size.cpp +++ b/examples/static_net/check/sonar_lin_avr_size.cpp @@ -2,12 +2,13 @@ // lin cell (arbitrary fold choice -- size shouldn't meaningfully depend on which // fold's constants are baked in, only on the shape: 60 In<> terms + Sign). #include "waveCell.h" +#include "inputs.h" #include "sonar_lin_params.h" volatile uint8_t in_[60]; volatile bool out_; int main(){ for(;;){ - wave::Features<60> f; for(int j=0;j<60;j++) f.v[j]=in_[j]; + inp::Bytes60 f; for(int j=0;j<60;j++) inp::band(f)[j]=in_[j]; out_=SonarLinFold0::proc(f); } } diff --git a/examples/static_net/check/sonar_lin_avr_size_wide.cpp b/examples/static_net/check/sonar_lin_avr_size_wide.cpp index 8dfd204..1df089d 100644 --- a/examples/static_net/check/sonar_lin_avr_size_wide.cpp +++ b/examples/static_net/check/sonar_lin_avr_size_wide.cpp @@ -2,12 +2,13 @@ // product computed at the full int32_t accumulator width (SonarLinFold0Wide) // instead of the int16_t product width (SonarLinFold0). See the README's Sonar table. #include "waveCell.h" +#include "inputs.h" #include "sonar_lin_params.h" volatile uint8_t in_[60]; volatile bool out_; int main(){ for(;;){ - wave::Features<60> f; for(int j=0;j<60;j++) f.v[j]=in_[j]; + inp::Bytes60 f; for(int j=0;j<60;j++) inp::band(f)[j]=in_[j]; out_=SonarLinFold0Wide::proc(f); } } diff --git a/examples/static_net/check/sonar_lin_check.cpp b/examples/static_net/check/sonar_lin_check.cpp index 759efe5..996af20 100644 --- a/examples/static_net/check/sonar_lin_check.cpp +++ b/examples/static_net/check/sonar_lin_check.cpp @@ -5,6 +5,7 @@ // accuracy -- two models can each be ~75% accurate while disagreeing on // different rows). #include "waveCell.h" +#include "inputs.h" #include "sonar_lin_params.h" #include "sonar_lin_vectors.h" #include @@ -13,8 +14,8 @@ template void check(const char* name,const uint8_t (&vec)[NVEC][62],double floatTrain,double floatTest){ int correct=0, agree=0; for(size_t i=0;i f; for(int j=0;j<60;j++) f.v[j]=vec[i][j]; - bool trueLabel=vec[i][60], floatPred=vec[i][61]; + inp::Bytes60 f; for(int j=0;j<60;j++) inp::band(f)[j]=vec[i][j]; + bool trueLabel=vec[i][SONAR_COL_LABEL], floatPred=vec[i][SONAR_COL_FLOAT]; bool intPred=Cell::proc(f); correct+=(intPred==trueLabel); agree+=(intPred==floatPred); diff --git a/examples/static_net/check/sugar_avr.cpp b/examples/static_net/check/sugar_avr.cpp index c9efd2d..04c6012 100644 --- a/examples/static_net/check/sugar_avr.cpp +++ b/examples/static_net/check/sugar_avr.cpp @@ -1,11 +1,12 @@ // the XOR net of sugar_check.cpp, written with sugar: size and code must equal sugar_hand_avr.cpp's (the same net by hand) #include "waveCell.h" +#include "inputs.h" #include "sugar.h" using namespace sugar; -constexpr auto a=x<0>; constexpr auto b=x<1>; +constexpr auto a=x; constexpr auto b=x; constexpr auto orr = cell<-1>(sign, w<2>*a, w<2>*b); constexpr auto nand = cell< 3>(sign, w<-2>*a, w<-2>*b); constexpr auto xr = cell<-3>(sign, w<2>*ref(orr), w<2>*ref(nand)); using Net = decltype(net(orr, nand, xr)); volatile uint8_t in_[2]; volatile int16_t out_; -int main(){ for(;;){ wave::Features<2> f{{in_[0],in_[1]}}; out_=Net::proc<2>(f);} } +int main(){ for(;;){ auto f=inp::ab({in_[0],in_[1]}); out_=Net::proc<2>(f);} } diff --git a/examples/static_net/check/sugar_check.cpp b/examples/static_net/check/sugar_check.cpp index d9d7117..bf87ca6 100644 --- a/examples/static_net/check/sugar_check.cpp +++ b/examples/static_net/check/sugar_check.cpp @@ -1,9 +1,10 @@ #include "waveCell.h" +#include "inputs.h" #include "sugar.h" #include using namespace sugar; -constexpr auto a=x<0>; -constexpr auto b=x<1>; +constexpr auto a=x; +constexpr auto b=x; constexpr auto orr = cell<-1>(sign, w<2>*a, w<2>*b); constexpr auto nand = cell< 3>(sign, w<-2>*a, w<-2>*b); constexpr auto xr = cell<-3>(sign, w<2>*ref(orr), w<2>*ref(nand)); @@ -11,11 +12,11 @@ using Net = decltype(net(orr, nand, xr)); // the same net written by hand, for comparison using Hand = snet::Net< - lin::Cell<-1,lin::Sign,lin::In<0,2>,lin::In<1,2>>, - lin::Cell< 3,lin::Sign,lin::In<0,-2>,lin::In<1,-2>>, + lin::Cell<-1,lin::Sign,lin::In,lin::In>, + lin::Cell< 3,lin::Sign,lin::In,lin::In>, lin::Cell<-3,lin::Sign,lin::RefIn<0,2>,lin::RefIn<1,2>>>; int main(){ int ok=1; - for(int p=0;p<2;p++)for(int q=0;q<2;q++){ wave::Features<2> f{{(wave::u8)p,(wave::u8)q}}; + for(int p=0;p<2;p++)for(int q=0;q<2;q++){ auto f=inp::ab({uint8_t(p),uint8_t(q)}); ok&=Net::proc<2>(f)==(p^q) && Hand::proc<2>(f)==(p^q); } printf("sizeof=%zu %s\n",sizeof(Net),ok?"ALL OK":"FAIL"); return !ok; } diff --git a/examples/static_net/check/sugar_cycle.cpp b/examples/static_net/check/sugar_cycle.cpp index 508111a..e81d760 100644 --- a/examples/static_net/check/sugar_cycle.cpp +++ b/examples/static_net/check/sugar_cycle.cpp @@ -1,8 +1,9 @@ #include "waveCell.h" +#include "inputs.h" #include "sugar.h" using namespace sugar; -constexpr auto a=x<0>; +constexpr auto a=x; constexpr auto c0 = cell<0>(sign, w<1>*a); constexpr auto c1 = cell<0>(sign, w<1>*ref(c0)); using Bad = decltype(net(c1, c0)); // c1 placed before the cell it reads -int main(){ wave::Features<1> f{{0}}; return Bad::proc<0>(f); } +int main(){ auto f=inp::one({0}); return Bad::proc<0>(f); } diff --git a/examples/static_net/check/sugar_hand_avr.cpp b/examples/static_net/check/sugar_hand_avr.cpp index 54eb9cf..e958cb9 100644 --- a/examples/static_net/check/sugar_hand_avr.cpp +++ b/examples/static_net/check/sugar_hand_avr.cpp @@ -1,9 +1,10 @@ // the XOR net of sugar_check.cpp written by hand, no sugar: the reference sugar_avr.cpp must equal #include "waveCell.h" +#include "inputs.h" #include "linCell.h" using Net = snet::Net< - lin::Cell<-1,lin::Sign,lin::In<0,2>,lin::In<1,2>>, - lin::Cell< 3,lin::Sign,lin::In<0,-2>,lin::In<1,-2>>, + lin::Cell<-1,lin::Sign,lin::In,lin::In>, + lin::Cell< 3,lin::Sign,lin::In,lin::In>, lin::Cell<-3,lin::Sign,lin::RefIn<0,2>,lin::RefIn<1,2>>>; volatile uint8_t in_[2]; volatile int16_t out_; -int main(){ for(;;){ wave::Features<2> f{{in_[0],in_[1]}}; out_=Net::proc<2>(f);} } +int main(){ for(;;){ auto f=inp::ab({in_[0],in_[1]}); out_=Net::proc<2>(f);} } diff --git a/examples/static_net/check/sugar_missing.cpp b/examples/static_net/check/sugar_missing.cpp index aedd5f6..058095a 100644 --- a/examples/static_net/check/sugar_missing.cpp +++ b/examples/static_net/check/sugar_missing.cpp @@ -1,11 +1,12 @@ // EXPECT-ERROR: sugar::ref: no cell of that type in the net // xr reads nand, but nand is not an argument of net(...): one clear message instead of an incomplete snet::IndexOf<...>. #include "waveCell.h" +#include "inputs.h" #include "sugar.h" using namespace sugar; -constexpr auto a=x<0>; +constexpr auto a=x; constexpr auto orr = cell<-1>(sign, w<2>*a); constexpr auto nand = cell< 3>(sign, w<-2>*a); constexpr auto xr = cell<-3>(sign, w<2>*ref(orr), w<2>*ref(nand)); using Bad = decltype(net(orr, xr)); -int main(){ wave::Features<1> f{{0}}; return Bad::proc<1>(f); } +int main(){ auto f=inp::one({0}); return Bad::proc<1>(f); } diff --git a/examples/static_net/check/sugar_roll.cpp b/examples/static_net/check/sugar_roll.cpp index d603643..2a06865 100644 --- a/examples/static_net/check/sugar_roll.cpp +++ b/examples/static_net/check/sugar_roll.cpp @@ -1,6 +1,7 @@ // sugar::cell picks the rolled form (snet::Roll) or the unrolled one (lin::Cell) from the term count, and the choice is invisible: // same result either way. Pinned: the types picked, what keeps a cell unrolled, and equality with the hand-written unrolled cell. #include "waveCell.h" +#include "inputs.h" #include "sugar.h" #include #include @@ -10,29 +11,29 @@ template using U=std::remove_cv_t; // decltype of static_assert(rollAt==6, "the measured threshold (see the README, Realizations); this test assumes it"); // 1. the type picked -constexpr auto a=x<0>; constexpr auto b=x<1>; constexpr auto c=x<2>; constexpr auto d=x<3>; constexpr auto e=x<4>; constexpr auto f5=x<5>; +constexpr auto a=x>; constexpr auto b=x>; constexpr auto c=x>; constexpr auto d=x>; constexpr auto e=x>; constexpr auto f5=x>; constexpr auto five = cell<7>(sign, w<2>*a, w<-3>*b, w<4>*c, w<-5>*d, w<6>*e); constexpr auto six = cell<7>(sign, w<2>*a, w<-3>*b, w<4>*c, w<-5>*d, w<6>*e, w<-7>*f5); -static_assert(std::is_same_v, lin::Cell<7,lin::Sign,lin::In<0,2>,lin::In<1,-3>,lin::In<2,4>,lin::In<3,-5>,lin::In<4,6>>>, "5 terms: unrolled"); +static_assert(std::is_same_v, lin::Cell<7,lin::Sign,lin::In,2>,lin::In,-3>,lin::In,4>,lin::In,-5>,lin::In,6>>>, "5 terms: unrolled"); static_assert(std::is_same_v, hapi::APIOf,snet::T<1,-3>,snet::T<2,4>,snet::T<3,-5>,snet::T<4,6>,snet::T<5,-7>>,lin::Bias<7>>>, "6 terms: rolled"); + snet::Roll,2>,snet::T,-3>,snet::T,4>,snet::T,-5>,snet::T,6>,snet::T,-7>>,lin::Bias<7>>>, "6 terms: rolled"); // what keeps a cell unrolled however many terms it has (six or more here): a weight that does not fit int8 (Roll would truncate it), // a term that reads another cell constexpr auto wide = cell<0>(sign, w<200>*a, w<1>*b, w<1>*c, w<1>*d, w<1>*e, w<1>*f5); -static_assert(std::is_same_v, lin::Cell<0,lin::Sign,lin::In<0,200>,lin::In<1,1>,lin::In<2,1>,lin::In<3,1>,lin::In<4,1>,lin::In<5,1>>>, "weight 200: unrolled"); +static_assert(std::is_same_v, lin::Cell<0,lin::Sign,lin::In,200>,lin::In,1>,lin::In,1>,lin::In,1>,lin::In,1>,lin::In,1>>>, "weight 200: unrolled"); constexpr auto first = cell<0>(sign, w<1>*a); constexpr auto withRef = cell<0>(sign, w<1>*ref(first), w<1>*b, w<1>*c, w<1>*d, w<1>*e, w<1>*f5); -static_assert(std::is_same_v, lin::Cell<0,lin::Sign,lin::Term>,1>,lin::In<1,1>,lin::In<2,1>,lin::In<3,1>,lin::In<4,1>,lin::In<5,1>>>, "a ref term: unrolled"); +static_assert(std::is_same_v, lin::Cell<0,lin::Sign,lin::Term>,1>,lin::In,1>,lin::In,1>,lin::In,1>,lin::In,1>,lin::In,1>>>, "a ref term: unrolled"); // 2. the same result: 8 terms (dense, then gapped and out of order) against the hand-written unrolled cell, on random inputs -constexpr auto dense8 = cell<-300>(sign, w<2>*x<0>, w<-3>*x<1>, w<127>*x<2>, w<-128>*x<3>, w<5>*x<4>, w<-6>*x<5>, w<7>*x<6>, w<-8>*x<7>); -constexpr auto gap8 = cell<-300>(sign, w<2>*x<9>, w<-3>*x<1>, w<127>*x<30>, w<-128>*x<1>, w<5>*x<59>, w<-6>*x<0>, w<7>*x<9>, w<-8>*x<7>); -static_assert(!std::is_same_v, lin::Cell<-300,lin::Sign,lin::In<0,2>,lin::In<1,-3>,lin::In<2,127>,lin::In<3,-128>,lin::In<4,5>,lin::In<5,-6>,lin::In<6,7>,lin::In<7,-8>>>, "8 terms: rolled"); +constexpr auto dense8 = cell<-300>(sign, w<2>*x>, w<-3>*x>, w<127>*x>, w<-128>*x>, w<5>*x>, w<-6>*x>, w<7>*x>, w<-8>*x>); +constexpr auto gap8 = cell<-300>(sign, w<2>*x>, w<-3>*x>, w<127>*x>, w<-128>*x>, w<5>*x>, w<-6>*x>, w<7>*x>, w<-8>*x>); +static_assert(!std::is_same_v, lin::Cell<-300,lin::Sign,lin::In,2>,lin::In,-3>,lin::In,127>,lin::In,-128>,lin::In,5>,lin::In,-6>,lin::In,7>,lin::In,-8>>>, "8 terms: rolled"); using SD = decltype(net(dense8)); using SG = decltype(net(gap8)); -using HD = snet::Net,lin::In<1,-3>,lin::In<2,127>,lin::In<3,-128>,lin::In<4,5>,lin::In<5,-6>,lin::In<6,7>,lin::In<7,-8>>>; -using HG = snet::Net,lin::In<1,-3>,lin::In<30,127>,lin::In<1,-128>,lin::In<59,5>,lin::In<0,-6>,lin::In<9,7>,lin::In<7,-8>>>; +using HD = snet::Net,2>,lin::In,-3>,lin::In,127>,lin::In,-128>,lin::In,5>,lin::In,-6>,lin::In,7>,lin::In,-8>>>; +using HG = snet::Net,2>,lin::In,-3>,lin::In,127>,lin::In,-128>,lin::In,5>,lin::In,-6>,lin::In,7>,lin::In,-8>>>; int main(){ int okD=0,okG=0,n=20000; srand(5); - for(int t=0;t f; for(int i=0;i<60;i++) f.v[i]=rand()&255; + for(int t=0;t(f)==HD::proc<0>(f); okG+=SG::proc<0>(f)==HG::proc<0>(f); } printf("sugar rolled==hand unrolled: dense %d/%d, gapped %d/%d\n",okD,n,okG,n); return okD!=n||okG!=n; } diff --git a/examples/static_net/check/sugar_roll_avr.cpp b/examples/static_net/check/sugar_roll_avr.cpp index 8022268..a947bd5 100644 --- a/examples/static_net/check/sugar_roll_avr.cpp +++ b/examples/static_net/check/sugar_roll_avr.cpp @@ -1,69 +1,70 @@ // a 60-term cell written with sugar: from SUGAR_ROLL_AT (6) terms sugar::cell picks the rolled form. Must equal sugar_roll_hand_avr.cpp // (the same cell with the Roll written out); compiled with -DSUGAR_ROLL_AT=1000 it must equal sugar_unroll_hand_avr.cpp instead. #include "waveCell.h" +#include "inputs.h" #include "sugar.h" using namespace sugar; constexpr auto c = cell<-2000>(sign, - w<-93>*x<0>, - w<18>*x<1>, - w<89>*x<2>, - w<78>*x<3>, - w<68>*x<4>, - w<-111>*x<5>, - w<-62>*x<6>, - w<-97>*x<7>, - w<-1>*x<8>, - w<67>*x<9>, - w<-12>*x<10>, - w<-7>*x<11>, - w<39>*x<12>, - w<-30>*x<13>, - w<74>*x<14>, - w<-74>*x<15>, - w<-103>*x<16>, - w<-3>*x<17>, - w<-120>*x<18>, - w<101>*x<19>, - w<86>*x<20>, - w<-28>*x<21>, - w<-17>*x<22>, - w<28>*x<23>, - w<68>*x<24>, - w<69>*x<25>, - w<-127>*x<26>, - w<51>*x<27>, - w<-13>*x<28>, - w<-59>*x<29>, - w<57>*x<30>, - w<78>*x<31>, - w<-69>*x<32>, - w<24>*x<33>, - w<114>*x<34>, - w<-101>*x<35>, - w<103>*x<36>, - w<-46>*x<37>, - w<-120>*x<38>, - w<-122>*x<39>, - w<-121>*x<40>, - w<39>*x<41>, - w<11>*x<42>, - w<-125>*x<43>, - w<113>*x<44>, - w<98>*x<45>, - w<-30>*x<46>, - w<48>*x<47>, - w<-72>*x<48>, - w<121>*x<49>, - w<-19>*x<50>, - w<58>*x<51>, - w<-120>*x<52>, - w<8>*x<53>, - w<-71>*x<54>, - w<68>*x<55>, - w<-15>*x<56>, - w<113>*x<57>, - w<-1>*x<58>, - w<14>*x<59>); + w<-93>*x>, + w<18>*x>, + w<89>*x>, + w<78>*x>, + w<68>*x>, + w<-111>*x>, + w<-62>*x>, + w<-97>*x>, + w<-1>*x>, + w<67>*x>, + w<-12>*x>, + w<-7>*x>, + w<39>*x>, + w<-30>*x>, + w<74>*x>, + w<-74>*x>, + w<-103>*x>, + w<-3>*x>, + w<-120>*x>, + w<101>*x>, + w<86>*x>, + w<-28>*x>, + w<-17>*x>, + w<28>*x>, + w<68>*x>, + w<69>*x>, + w<-127>*x>, + w<51>*x>, + w<-13>*x>, + w<-59>*x>, + w<57>*x>, + w<78>*x>, + w<-69>*x>, + w<24>*x>, + w<114>*x>, + w<-101>*x>, + w<103>*x>, + w<-46>*x>, + w<-120>*x>, + w<-122>*x>, + w<-121>*x>, + w<39>*x>, + w<11>*x>, + w<-125>*x>, + w<113>*x>, + w<98>*x>, + w<-30>*x>, + w<48>*x>, + w<-72>*x>, + w<121>*x>, + w<-19>*x>, + w<58>*x>, + w<-120>*x>, + w<8>*x>, + w<-71>*x>, + w<68>*x>, + w<-15>*x>, + w<113>*x>, + w<-1>*x>, + w<14>*x>); using Net = decltype(net(c)); volatile uint8_t in_[60]; volatile int16_t out_; -int main(){ for(;;){ wave::Features<60> f; for(int i=0;i<60;i++) f.v[i]=in_[i]; out_=Net::proc<0>(f);} } +int main(){ for(;;){ inp::Bytes60 f; for(int i=0;i<60;i++) inp::band(f)[i]=in_[i]; out_=Net::proc<0>(f);} } diff --git a/examples/static_net/check/sugar_roll_hand_avr.cpp b/examples/static_net/check/sugar_roll_hand_avr.cpp index 8728f53..97321a3 100644 --- a/examples/static_net/check/sugar_roll_hand_avr.cpp +++ b/examples/static_net/check/sugar_roll_hand_avr.cpp @@ -1,7 +1,8 @@ // the cell of sugar_roll_avr.cpp with the rolled form written out by hand, no sugar: what sugar::cell must pick from 6 terms up #include "waveCell.h" +#include "inputs.h" #include "linCell.h" #include "roll.h" -using Net = snet::Net,snet::T<1,18>,snet::T<2,89>,snet::T<3,78>,snet::T<4,68>,snet::T<5,-111>,snet::T<6,-62>,snet::T<7,-97>,snet::T<8,-1>,snet::T<9,67>,snet::T<10,-12>,snet::T<11,-7>,snet::T<12,39>,snet::T<13,-30>,snet::T<14,74>,snet::T<15,-74>,snet::T<16,-103>,snet::T<17,-3>,snet::T<18,-120>,snet::T<19,101>,snet::T<20,86>,snet::T<21,-28>,snet::T<22,-17>,snet::T<23,28>,snet::T<24,68>,snet::T<25,69>,snet::T<26,-127>,snet::T<27,51>,snet::T<28,-13>,snet::T<29,-59>,snet::T<30,57>,snet::T<31,78>,snet::T<32,-69>,snet::T<33,24>,snet::T<34,114>,snet::T<35,-101>,snet::T<36,103>,snet::T<37,-46>,snet::T<38,-120>,snet::T<39,-122>,snet::T<40,-121>,snet::T<41,39>,snet::T<42,11>,snet::T<43,-125>,snet::T<44,113>,snet::T<45,98>,snet::T<46,-30>,snet::T<47,48>,snet::T<48,-72>,snet::T<49,121>,snet::T<50,-19>,snet::T<51,58>,snet::T<52,-120>,snet::T<53,8>,snet::T<54,-71>,snet::T<55,68>,snet::T<56,-15>,snet::T<57,113>,snet::T<58,-1>,snet::T<59,14>>,lin::Bias<-2000>>>; +using Net = snet::Net,-93>,snet::T,18>,snet::T,89>,snet::T,78>,snet::T,68>,snet::T,-111>,snet::T,-62>,snet::T,-97>,snet::T,-1>,snet::T,67>,snet::T,-12>,snet::T,-7>,snet::T,39>,snet::T,-30>,snet::T,74>,snet::T,-74>,snet::T,-103>,snet::T,-3>,snet::T,-120>,snet::T,101>,snet::T,86>,snet::T,-28>,snet::T,-17>,snet::T,28>,snet::T,68>,snet::T,69>,snet::T,-127>,snet::T,51>,snet::T,-13>,snet::T,-59>,snet::T,57>,snet::T,78>,snet::T,-69>,snet::T,24>,snet::T,114>,snet::T,-101>,snet::T,103>,snet::T,-46>,snet::T,-120>,snet::T,-122>,snet::T,-121>,snet::T,39>,snet::T,11>,snet::T,-125>,snet::T,113>,snet::T,98>,snet::T,-30>,snet::T,48>,snet::T,-72>,snet::T,121>,snet::T,-19>,snet::T,58>,snet::T,-120>,snet::T,8>,snet::T,-71>,snet::T,68>,snet::T,-15>,snet::T,113>,snet::T,-1>,snet::T,14>>,lin::Bias<-2000>>>; volatile uint8_t in_[60]; volatile int16_t out_; -int main(){ for(;;){ wave::Features<60> f; for(int i=0;i<60;i++) f.v[i]=in_[i]; out_=Net::proc<0>(f);} } +int main(){ for(;;){ inp::Bytes60 f; for(int i=0;i<60;i++) inp::band(f)[i]=in_[i]; out_=Net::proc<0>(f);} } diff --git a/examples/static_net/check/sugar_twins.cpp b/examples/static_net/check/sugar_twins.cpp index 7c40c25..51d0670 100644 --- a/examples/static_net/check/sugar_twins.cpp +++ b/examples/static_net/check/sugar_twins.cpp @@ -1,10 +1,11 @@ // Cells of identical type are one cell to ref(): it resolves to the first. Intended: identical pure cells compute the same value, // so that is deduplication. Pinned here so a change to it is a decision, not an accident. #include "waveCell.h" +#include "inputs.h" #include "sugar.h" #include using namespace sugar; -constexpr auto a=x<0>; +constexpr auto a=x; constexpr auto c0 = cell<0>(sign, w<1>*a); constexpr auto c1 = cell<0>(sign, w<1>*a); // the same type as c0 static_assert(std::is_same_v); @@ -13,5 +14,5 @@ using N = decltype(net(c0, c1, c2)); template using U=std::remove_cv_t; // decltype of a constexpr variable is const; the net holds the plain type static_assert(CellIndex,N::Cells>::value==0, "ref(c1) resolves to the first cell of that type"); static_assert(CellIndex,N::Cells>::value==2); -int main(){ int ok=1; for(int p=0;p<2;p++){ wave::Features<1> f{{(wave::u8)p}}; ok&=N::proc<2>(f)==(p>0); } +int main(){ int ok=1; for(int p=0;p<2;p++){ auto f=inp::one({uint8_t(p)}); ok&=N::proc<2>(f)==(p>0); } printf("twins %s\n",ok?"OK":"FAIL"); return !ok; } diff --git a/examples/static_net/check/sugar_unroll_hand_avr.cpp b/examples/static_net/check/sugar_unroll_hand_avr.cpp index f25ff51..f24b033 100644 --- a/examples/static_net/check/sugar_unroll_hand_avr.cpp +++ b/examples/static_net/check/sugar_unroll_hand_avr.cpp @@ -1,6 +1,7 @@ // the cell of sugar_roll_avr.cpp unrolled by hand, no sugar: what sugar::cell gives with -DSUGAR_ROLL_AT=1000 #include "waveCell.h" +#include "inputs.h" #include "linCell.h" -using Net = snet::Net,lin::In<1,18>,lin::In<2,89>,lin::In<3,78>,lin::In<4,68>,lin::In<5,-111>,lin::In<6,-62>,lin::In<7,-97>,lin::In<8,-1>,lin::In<9,67>,lin::In<10,-12>,lin::In<11,-7>,lin::In<12,39>,lin::In<13,-30>,lin::In<14,74>,lin::In<15,-74>,lin::In<16,-103>,lin::In<17,-3>,lin::In<18,-120>,lin::In<19,101>,lin::In<20,86>,lin::In<21,-28>,lin::In<22,-17>,lin::In<23,28>,lin::In<24,68>,lin::In<25,69>,lin::In<26,-127>,lin::In<27,51>,lin::In<28,-13>,lin::In<29,-59>,lin::In<30,57>,lin::In<31,78>,lin::In<32,-69>,lin::In<33,24>,lin::In<34,114>,lin::In<35,-101>,lin::In<36,103>,lin::In<37,-46>,lin::In<38,-120>,lin::In<39,-122>,lin::In<40,-121>,lin::In<41,39>,lin::In<42,11>,lin::In<43,-125>,lin::In<44,113>,lin::In<45,98>,lin::In<46,-30>,lin::In<47,48>,lin::In<48,-72>,lin::In<49,121>,lin::In<50,-19>,lin::In<51,58>,lin::In<52,-120>,lin::In<53,8>,lin::In<54,-71>,lin::In<55,68>,lin::In<56,-15>,lin::In<57,113>,lin::In<58,-1>,lin::In<59,14>>>; +using Net = snet::Net,-93>,lin::In,18>,lin::In,89>,lin::In,78>,lin::In,68>,lin::In,-111>,lin::In,-62>,lin::In,-97>,lin::In,-1>,lin::In,67>,lin::In,-12>,lin::In,-7>,lin::In,39>,lin::In,-30>,lin::In,74>,lin::In,-74>,lin::In,-103>,lin::In,-3>,lin::In,-120>,lin::In,101>,lin::In,86>,lin::In,-28>,lin::In,-17>,lin::In,28>,lin::In,68>,lin::In,69>,lin::In,-127>,lin::In,51>,lin::In,-13>,lin::In,-59>,lin::In,57>,lin::In,78>,lin::In,-69>,lin::In,24>,lin::In,114>,lin::In,-101>,lin::In,103>,lin::In,-46>,lin::In,-120>,lin::In,-122>,lin::In,-121>,lin::In,39>,lin::In,11>,lin::In,-125>,lin::In,113>,lin::In,98>,lin::In,-30>,lin::In,48>,lin::In,-72>,lin::In,121>,lin::In,-19>,lin::In,58>,lin::In,-120>,lin::In,8>,lin::In,-71>,lin::In,68>,lin::In,-15>,lin::In,113>,lin::In,-1>,lin::In,14>>>; volatile uint8_t in_[60]; volatile int16_t out_; -int main(){ for(;;){ wave::Features<60> f; for(int i=0;i<60;i++) f.v[i]=in_[i]; out_=Net::proc<0>(f);} } +int main(){ for(;;){ inp::Bytes60 f; for(int i=0;i<60;i++) inp::band(f)[i]=in_[i]; out_=Net::proc<0>(f);} } diff --git a/examples/static_net/compare_emlearn/bnc.cpp b/examples/static_net/compare_emlearn/bnc.cpp index f7054f4..f705591 100644 --- a/examples/static_net/compare_emlearn/bnc.cpp +++ b/examples/static_net/compare_emlearn/bnc.cpp @@ -1,3 +1,4 @@ -// one Banknote program: -DBNC_MODEL='"models/x.h"' -DBNC_NAME='"x"' (run.sh). The model header comes first: it defines bnc_predict(). +// one Banknote program: -DBNC_MODEL='"models/x.h"' -DBNC_NAME='"x"' (run.sh). The rows header comes first (the column names), then the model header, which defines bnc_predict(). +#include "bnc_rows.h" // the column names (BNC_COL_*) come first: the model headers use them #include BNC_MODEL #include "bnc_common.h" diff --git a/examples/static_net/compare_emlearn/bnc_lin.h b/examples/static_net/compare_emlearn/bnc_lin.h index da59e67..f61ecf3 100644 --- a/examples/static_net/compare_emlearn/bnc_lin.h +++ b/examples/static_net/compare_emlearn/bnc_lin.h @@ -1,5 +1,6 @@ // generated by gen_models.py: lin4 = fold 1's float perceptron quantized (scale 4.97084): int8 weights, int32 accumulator, int16 product #include "waveCell.h" #include "linCell.h" -using BncLin = lin::CellOf,lin::InOf,lin::InOf,lin::InOf,lin::InOf>; -__attribute__((noinline)) bool bnc_predict(const uint8_t* x){ wave::Features<4> f{{x[0],x[1],x[2],x[3]}}; return snet::Net::proc<0>(f); } +#include "net.h" +using BncLin = lin::CellOf,lin::InOf,lin::InOf,lin::InOf,lin::InOf>; +__attribute__((noinline)) bool bnc_predict(const uint8_t* x){ BanknoteState f = banknote({x[BNC_COL_VARIANCE],x[BNC_COL_SKEWNESS],x[BNC_COL_CURTOSIS],x[BNC_COL_ENTROPY]}); return snet::Net::proc<0>(f); } diff --git a/examples/static_net/compare_emlearn/bnc_rows.h b/examples/static_net/compare_emlearn/bnc_rows.h index 89e62e9..f342eb4 100644 --- a/examples/static_net/compare_emlearn/bnc_rows.h +++ b/examples/static_net/compare_emlearn/bnc_rows.h @@ -3,6 +3,10 @@ #include #include #define BNC_N 274 +#define BNC_COL_VARIANCE 0 +#define BNC_COL_SKEWNESS 1 +#define BNC_COL_CURTOSIS 2 +#define BNC_COL_ENTROPY 3 static const uint8_t BNC_X[BNC_N][4] PROGMEM = { {122,132,57,193}, {112,71,120,228}, diff --git a/examples/static_net/compare_emlearn/bnc_wave.h b/examples/static_net/compare_emlearn/bnc_wave.h index e53b6af..d02f75b 100644 --- a/examples/static_net/compare_emlearn/bnc_wave.h +++ b/examples/static_net/compare_emlearn/bnc_wave.h @@ -1,3 +1,3 @@ // wave4: the trained Banknote wave cell of fold 1 (../models/banknote/net.h, wave_params.h): no multiply, no table, no RAM. #include "net.h" -__attribute__((noinline)) bool bnc_predict(const uint8_t* x){ wave::Features<4> f{{x[0],x[1],x[2],x[3]}}; return BanknoteNet::proc(f); } +__attribute__((noinline)) bool bnc_predict(const uint8_t* x){ BanknoteState f = banknote({x[BNC_COL_VARIANCE],x[BNC_COL_SKEWNESS],x[BNC_COL_CURTOSIS],x[BNC_COL_ENTROPY]}); return BanknoteNet::proc(f); } diff --git a/examples/static_net/compare_emlearn/gen_models.py b/examples/static_net/compare_emlearn/gen_models.py index ad56d00..8990d04 100644 --- a/examples/static_net/compare_emlearn/gen_models.py +++ b/examples/static_net/compare_emlearn/gen_models.py @@ -54,9 +54,12 @@ def record(name, accs, **extra): wv = np.array([[int(v) for v in r] for r in wv]) assert wv.shape[0] == len(Xte1) and (wv[:, :4] == Xte1).all() and (wv[:, 4] == yte1).all(), "fold 1 of the export is not the fold of wave_vectors.h" print('fold 1 held-out rows: %d, identical to ../models/banknote/wave_vectors.h' % len(Xte1)) +# the columns of bn.csv, in order (UCI Banknote Authentication); the rows, the cells' inputs and the column macros below are named by these +FEATURES = ['variance', 'skewness', 'curtosis', 'entropy'] with open(os.path.join(HERE, 'bnc_rows.h'), 'w') as o: o.write('#pragma once\n// generated by gen_models.py: fold 1\'s held-out rows (quantized with fold 1\'s train min/max) and their labels, in flash\n') o.write('#include \n#include \n#define BNC_N %d\n' % len(Xte1)) + o.write(''.join('#define BNC_COL_%s %d\n' % (f.upper(), i) for i, f in enumerate(FEATURES))) o.write('static const uint8_t BNC_X[BNC_N][4] PROGMEM = {\n' + ',\n'.join(' {%d,%d,%d,%d}' % tuple(r) for r in Xte1) + '\n};\n') o.write('static const uint8_t BNC_Y[BNC_N] PROGMEM = {' + ','.join(str(v) for v in yte1) + '};\n') @@ -81,11 +84,11 @@ def record(name, accs, **extra): record('lin4', lin_accs, weights_fold1=lin1[0], bias_fold1=lin1[1], note='float perceptron of bn2.c quantized: int8 weights, int32 accumulator') record('table4', lin_accs, note='same weights as lin4, a loop over a PROGMEM table: same answers by construction') wq, bq, scale = lin1 -terms = ','.join('lin::InOf' % (i, wq[i]) for i in range(4)) +terms = ','.join('lin::InOf' % (FEATURES[i].capitalize(), wq[i]) for i in range(4)) open(os.path.join(HERE, 'bnc_lin.h'), 'w').write( '// generated by gen_models.py: lin4 = fold 1\'s float perceptron quantized (scale %.6g): int8 weights, int32 accumulator, int16 product\n' - '#include "waveCell.h"\n#include "linCell.h"\nusing BncLin = lin::CellOf,%s>;\n' - '__attribute__((noinline)) bool bnc_predict(const uint8_t* x){ wave::Features<4> f{{x[0],x[1],x[2],x[3]}}; return snet::Net::proc<0>(f); }\n' % (scale, bq, terms)) + '#include "waveCell.h"\n#include "linCell.h"\n#include "net.h"\nusing BncLin = lin::CellOf,%s>;\n' + '__attribute__((noinline)) bool bnc_predict(const uint8_t* x){ BanknoteState f = banknote({x[BNC_COL_VARIANCE],x[BNC_COL_SKEWNESS],x[BNC_COL_CURTOSIS],x[BNC_COL_ENTROPY]}); return snet::Net::proc<0>(f); }\n' % (scale, bq, terms)) open(os.path.join(HERE, 'bnc_table.h'), 'w').write( '// generated by gen_models.py: table4 = the weights of bnc_lin.h in a PROGMEM table and a loop\n#include \n#include \n' 'static const int8_t BNC_W[4] PROGMEM = {%s};\n' diff --git a/examples/static_net/include/inputs.h b/examples/static_net/include/inputs.h new file mode 100644 index 0000000..e42585b --- /dev/null +++ b/examples/static_net/include/inputs.h @@ -0,0 +1,25 @@ +#pragma once +// inputs.h — stock input layers for nets whose inputs have no model of their own: the state is one slot, and a source names the field it reads. +// inp::One a inp::Ab a, b inp::Bytes60 band[60] (one 60-element input vector) +#include "staticNet.h" + +namespace inp { + struct OneTag {}; + struct SlotOne { uint8_t a; }; + using One = hapi::APIOf>::Res; + using OneA = snet::Field; + inline One one(const SlotOne& in) { One r; hapi::slot(r) = in; return r; } // one({a}): a braced list is evaluated left to right + + struct AbTag {}; + struct SlotAb { uint8_t a, b; }; + using Ab = hapi::APIOf>::Res; + using A = snet::Field; + using B = snet::Field; + inline Ab ab(const SlotAb& in) { Ab r; hapi::slot(r) = in; return r; } // ab({a, b}) + + struct BytesTag {}; + struct SlotBytes60 { uint8_t band[60]; }; + using Bytes60 = hapi::APIOf>::Res; + template using Band = snet::Elem; // element k of the input vector + inline uint8_t (&band(Bytes60& r))[60] { return hapi::slot(r).band; } +} diff --git a/examples/static_net/include/linCell.h b/examples/static_net/include/linCell.h index d1cdd60..ddcc9da 100644 --- a/examples/static_net/include/linCell.h +++ b/examples/static_net/include/linCell.h @@ -4,7 +4,7 @@ #include namespace lin { - using snet::Net; using snet::Slot; using snet::Ref; + using snet::Net; using snet::Ref; // accumulator width is a template parameter: fan-in x max|input| x max|weight| // must fit, same constraint that limited the u8 wave cell on Sonar one level @@ -13,7 +13,6 @@ namespace lin { template struct APIOf { template SNET_INLINE static constexpr Acc proc(const I&) {return 0;} - template SNET_INLINE static constexpr void update(I&) {} }; template struct BiasOf {template struct Part:O { using Base=O; using Base::Base; @@ -36,7 +35,7 @@ namespace lin { return Acc(Acc(Prod(w)*Prod(Src::get(in)))+Base::proc(in)); } };}; - template using InOf=TermOf,w>; + template using InOf=TermOf; // Src: a Field or Elem of the state template using RefInOf=TermOf,w>; template struct SignOf {template struct Part:O { using Base=O; using Base::Base; @@ -52,7 +51,7 @@ namespace lin { using API=APIOf; template using Bias=BiasOf; template using Term=TermOf; - template using In=InOf; + template using In=InOf; template using RefIn=RefInOf; using Sign=SignOf; template using Cell=CellOf; diff --git a/examples/static_net/include/registers.h b/examples/static_net/include/registers.h new file mode 100644 index 0000000..7ce4d1d --- /dev/null +++ b/examples/static_net/include/registers.h @@ -0,0 +1,36 @@ +#pragma once +// registers.h — a value that survives from one pass to the next, as a layer of the state. +// Cells stay `proc(in)` and pure; the layer is the register: its step evaluates cells on `prev` (the whole previous state, so registers +// that read each other all see the old values) and stores the new slot. Fields no Reg names keep their previous value. +// struct Slot { uint8_t a, b; }; +// using Regs = snet::Registers, snet::Reg<&Slot::b, CellNextB>>; +// using State = hapi::APIOf>::Res; state.step(prev): the layers after this one first +#include "staticNet.h" + +namespace snet { + template struct Reg { // M: the field (a member pointer) that receives the cell's value + template SNET_INLINE static void apply(S& s, const P& prev) {s.*M = Cell::proc(prev);} + }; + template struct Registers { + template static auto run(const Below&, const Prev& prev) { + auto s = hapi::slot(prev); + (RR::apply(s, prev), ...); + return s; + } + }; + + // the state's step: the layers after this one first, then this layer's registers; a layer without a Body holds its value + struct RegRoot : hapi::SlotRoot { template void step(const P&) {} }; + struct RegApi { using Res = RegRoot; }; + template struct StepOf { + template struct Type : Below { + template void step(const P& prev) { + Below::step(prev); + R& self = static_cast(*this); + if constexpr (std::is_same::value) self.me() = hapi::slot(prev); + else self.me() = Body::run(static_cast(self), prev); + } + }; + }; + template using RegLayer = hapi::Slot::template Type>; +} diff --git a/examples/static_net/include/roll.h b/examples/static_net/include/roll.h index f866fbf..c15266a 100644 --- a/examples/static_net/include/roll.h +++ b/examples/static_net/include/roll.h @@ -1,5 +1,5 @@ #pragma once -// roll.h — a Part component whose static body (a pack of terms) is materialized as a table and iterated. +// roll.h — a Part component whose static body (a pack of terms over one array field) is materialized as a table and iterated. // Same terms as the unrolled form; only the realization differs. #include "staticNet.h" #include @@ -15,12 +15,12 @@ #endif namespace snet { - // term record: input index and weight (also usable as an unrolled Part, see W below) - template struct T { - static constexpr size_t index=i; static constexpr int weight=w; + // term record: an element of an array field (Elem) and a weight (also usable as an unrolled Part, see W below) + template struct T { + static constexpr size_t index=Src::index; static constexpr int weight=w; using Source=Src; template struct Part:O { using Base=O; using Base::Base; template SNET_INLINE static constexpr auto proc(const I& in) - {return decltype(Base::proc(in))(int16_t(int16_t(w)*int16_t(in.template get())))+Base::proc(in);} + {return decltype(Base::proc(in))(int16_t(int16_t(w)*int16_t(Src::get(in))))+Base::proc(in);} }; }; @@ -29,18 +29,26 @@ namespace snet { template struct IsIota {static constexpr bool value=true;}; template struct IsIota {static constexpr bool value=(i==k)&&IsIota::value;}; - // rolled realization of a pack of T; index column only when indices aren't 0..N-1 + // the array field a pack of terms reads: every term must be an element of the same one + template struct SameArray {static constexpr bool value=true;}; + template struct SameArray,Elem,SS...> {static constexpr bool value=SameArray,SS...>::value;}; + template struct SameArray {static constexpr bool value=false;}; + + // rolled realization of a pack of T; index column only when indices aren't 0..N-1 template struct Roll {template struct Part:O { using Base=O; using Base::Base; static constexpr size_t n=sizeof...(TT); + static_assert(SameArray::value,"snet::Roll: every term must read an element of the same array field"); static_assert(((TT::weight>=-128&&TT::weight<=127)&&...),"snet::Roll: a weight does not fit int8 (the table stores bytes)"); static_assert(((TT::index<256)&&...),"snet::Roll: an input index does not fit a byte"); static constexpr bool dense=IsIota<0,TT::index...>::value; static constexpr int8_t w[n] SNET_ROM = {int8_t(TT::weight)...}; static constexpr uint8_t ix[n] SNET_ROM = {uint8_t(TT::index)...}; + template SNET_INLINE static const uint8_t* base(const Elem*,const I& in) + {return hapi::slot(stateOf(in)).*M;} template SNET_INLINE static auto proc(const I& in) { auto a=Base::proc(in); - const uint8_t* x=in.data(); + const uint8_t* x=base(static_cast::Head*>(nullptr),in); for(uint8_t k=0;k #include #include @@ -12,28 +14,34 @@ #endif namespace snet { - // state view: net and current cell index as phantom types, holds only a reference + // state view: net and current cell index as phantom types, holds only a reference to the state template struct Ctx { using Net=N; static constexpr size_t cur=k; S& s; template SNET_INLINE constexpr Ctx at() const {return {s};} - template SNET_INLINE constexpr decltype(auto) get() const {return s.template get();} - template SNET_INLINE constexpr void set(V x) const {s.template set(x);} - SNET_INLINE constexpr auto data() const {return s.data();} // the raw slot bytes, for parts that iterate over them (roll.h) }; + // the state behind a view: through Net<...>::proc a source gets a Ctx, evaluated on a cell directly it gets the state itself + template SNET_INLINE constexpr const S& stateOf(const Ctx& c) {return c.s;} + template SNET_INLINE constexpr const S& stateOf(const S& s) {return s;} + // in-place reference to cell j of the enclosing net (same pass, pure, CSE-foldable) template struct Ref { template SNET_INLINE static constexpr auto get(const I& in) { - static_assert(j: in-place reference must point to a lower net index; a cycle needs a register (Slot + Store)"); + static_assert(j: in-place reference must point to a lower net index; a cycle needs a register (a typed layer that evaluates the cell on prev)"); return I::Net::template Cell::proc(in.template at()); } }; - // state slot i: a true input edge, or a register written by a Store - template struct Slot { - template SNET_INLINE static constexpr auto get(const I& in) {return in.template get();} + // a value that lives in the state: the field M (a member pointer) of the slot of layer Tag + template struct Field { + template SNET_INLINE static constexpr auto get(const I& in) {return hapi::slot(stateOf(in)).*M;} + }; + // element k of an array field + template struct Elem { + static constexpr size_t index=k; + template SNET_INLINE static constexpr auto get(const I& in) {return (hapi::slot(stateOf(in)).*M)[k];} }; template struct Net { @@ -41,8 +49,6 @@ namespace snet { template using Cell=typename Cells::template Drop::Head; template SNET_INLINE static constexpr auto proc(S& s) {return Cell::proc(Ctx{s});} - template SNET_INLINE static constexpr void update(S& s) - {Ctx c{s}; Cell::update(c);} }; } diff --git a/examples/static_net/include/sugar.h b/examples/static_net/include/sugar.h index a974326..6c10cc4 100644 --- a/examples/static_net/include/sugar.h +++ b/examples/static_net/include/sugar.h @@ -6,7 +6,7 @@ namespace sugar { template struct X {}; // a source: input slot or another cell - template constexpr X> x{}; + template constexpr X x{}; // Src: a Field or Elem of the state template struct W {}; template constexpr W w{}; @@ -58,17 +58,17 @@ namespace sugar { inline constexpr size_t rollAt=SUGAR_ROLL_AT; namespace detail { - // a term the rolled form can hold: an input slot (Roll reads the raw slot bytes), an index that fits a byte and an int8 weight + // a term the rolled form can hold: an element of an array field, an index that fits a byte and an int8 weight // (Roll stores both as bytes; a wider weight would be truncated silently, so such a cell stays unrolled) - template struct RollTerm {static constexpr bool ok=false;}; - template struct RollTerm,w>> { + template struct RollTerm {static constexpr bool ok=false; using source=void;}; + template struct RollTerm,w>> { static constexpr bool ok=(i<256)&&(w>=-128)&&(w<=127); - using type=snet::T; + using type=snet::T,int(w)>; using source=snet::Elem; }; } template constexpr auto cell(R,TT...) { - if constexpr (sizeof...(TT)>=rollAt && (detail::RollTerm::ok && ...)) + if constexpr (sizeof...(TT)>=rollAt && (detail::RollTerm::ok && ...) && snet::SameArray::source...>::value) return hapi::APIOf::type...>,lin::Bias>{}; else return lin::Cell{}; diff --git a/examples/static_net/include/waveCell.h b/examples/static_net/include/waveCell.h index f3c9a31..2189eb9 100644 --- a/examples/static_net/include/waveCell.h +++ b/examples/static_net/include/waveCell.h @@ -6,11 +6,10 @@ namespace wave { using u8=uint8_t; // not µ: UTF-8 identifiers need GCC>=10, avr-gcc 7.3 rejects them - using snet::Net; using snet::Slot; using snet::Ref; + using snet::Net; using snet::Ref; struct API { template SNET_INLINE static constexpr u8 proc(const I&) {return 0;} - template SNET_INLINE static constexpr void update(I&) {} }; // global phase offset @@ -29,7 +28,7 @@ namespace wave { template SNET_INLINE static constexpr u8 proc(const I& in) {return u8(u8(u8(shf(inv(u8(Src::get(in))))+p)&m)+Base::proc(in));} };}; - template using Wave=WaveOf,n,s,p,m>; + template using Wave=WaveOf; // Src: a Field or Elem of the state template using RefWave=WaveOf,n,s,p,m>; // readout of bit 7 (phase < half) @@ -38,23 +37,6 @@ namespace wave { template SNET_INLINE static constexpr bool proc(const I& in) {return Base::proc(in)<128;} };}; - // writes the running proc() value at this point into state slot i, then chains to the next Store - template - struct Store {template struct Part:O { - using Base=O; using Base::Base; - template SNET_INLINE static constexpr void update(I& in) { - in.template set(Base::proc(in)); - Base::update(in); - } - };}; - template using Cell=hapi::APIOf>; - // input state passed by value/reference, no global reads (CSE-eligible) - template struct Features { - u8 v[N]; - template constexpr u8 get() const {return v[i];} - template constexpr void set(u8 x) {v[i]=x;} - constexpr const u8* data() const {return v;} - }; } diff --git a/examples/static_net/measure/bn_lin.cpp b/examples/static_net/measure/bn_lin.cpp index da668d0..838f84d 100644 --- a/examples/static_net/measure/bn_lin.cpp +++ b/examples/static_net/measure/bn_lin.cpp @@ -1,8 +1,9 @@ #include "harness.h" #include "waveCell.h" #include "linCell.h" -using L=lin::Cell<-300,lin::Sign,lin::In<0,37>,lin::In<1,-91>,lin::In<2,12>,lin::In<3,-5>>; +#include "net.h" +using L=lin::Cell<-300,lin::Sign,lin::In,lin::In,lin::In,lin::In>; using N=snet::Net; volatile uint8_t in_[4]={10,200,30,99}; volatile uint8_t out_; -int main(){ uinit(); wave::Features<4> f{{in_[0],in_[1],in_[2],in_[3]}}; +int main(){ uinit(); BanknoteState f=banknote({in_[0],in_[1],in_[2],in_[3]}); MEASURE("lin4:", out_=N::proc<0>(f)); done(); } diff --git a/examples/static_net/measure/bn_wave.cpp b/examples/static_net/measure/bn_wave.cpp index 9ef24c8..d35cec2 100644 --- a/examples/static_net/measure/bn_wave.cpp +++ b/examples/static_net/measure/bn_wave.cpp @@ -1,5 +1,5 @@ #include "harness.h" #include "net.h" volatile uint8_t in_[4]={10,200,30,99}; volatile uint8_t out_; -int main(){ uinit(); wave::Features<4> f{{in_[0],in_[1],in_[2],in_[3]}}; - MEASURE("wave4:", {uint8_t a=f.v[0],b=f.v[1],c=f.v[2],d=f.v[3]; KEEP(a);KEEP(b);KEEP(c);KEEP(d); f.v[0]=a;f.v[1]=b;f.v[2]=c;f.v[3]=d; bool r=BanknoteNet::proc(f); KEEP(r); out_=r;}); done(); } +int main(){ uinit(); BanknoteState f=banknote({in_[0],in_[1],in_[2],in_[3]}); + MEASURE("wave4:", {BanknoteIn& s=hapi::slot(f); uint8_t a=s.variance,b=s.skewness,c=s.curtosis,d=s.entropy; KEEP(a);KEEP(b);KEEP(c);KEEP(d); s.variance=a;s.skewness=b;s.curtosis=c;s.entropy=d; bool r=BanknoteNet::proc(f); KEEP(r); out_=r;}); done(); } diff --git a/examples/static_net/measure/roll_sweep.sh b/examples/static_net/measure/roll_sweep.sh index 5044b46..b0e4d0e 100755 --- a/examples/static_net/measure/roll_sweep.sh +++ b/examples/static_net/measure/roll_sweep.sh @@ -7,19 +7,19 @@ W="-93,18,89,78,68,-111,-62,-97,-1,67,-12,-7,39,-30,74,-74,-103,-3,-120,101,86,- gen(){ python3 - "$1" "$2" "$3" "$W" <<'PY' import sys N=int(sys.argv[1]); form=sys.argv[2]; kind=sys.argv[3]; W=[int(v) for v in sys.argv[4].split(",")] -if form=='u': net="snet::Net>"%",".join("lin::In<%d,%d>"%(i,W[i]) for i in range(N)) -else: net="snet::Net,lin::Bias<-2000>>>"%",".join("snet::T<%d,%d>"%(i,W[i]) for i in range(N)) -hdr='#include "waveCell.h"\n#include "linCell.h"\n#include "roll.h"\n' +if form=='u': net="snet::Net>"%",".join("lin::In,%d>"%(i,W[i]) for i in range(N)) +else: net="snet::Net,lin::Bias<-2000>>>"%",".join("snet::T,%d>"%(i,W[i]) for i in range(N)) +hdr='#include "waveCell.h"\n#include "linCell.h"\n#include "roll.h"\n#include "inputs.h"\n' if kind=='cyc': print('#include "harness.h"\n'+hdr+"using NetT=%s;"%net) print("volatile uint8_t x[%d]; volatile uint8_t out_;"%N) - print("__attribute__((noinline)) bool cls(wave::Features<%d>& f){ return NetT::proc<0>(f); }"%N) - print("int main(){ uinit(); wave::Features<%d> f; for(int i=0;i<%d;i++) f.v[i]=x[i]^(i*37);"%(N,N)) + print("__attribute__((noinline)) bool cls(inp::Bytes60& f){ return NetT::proc<0>(f); }") + print("int main(){ uinit(); inp::Bytes60 f; for(int i=0;i<%d;i++) inp::band(f)[i]=x[i]^(i*37);"%N) print(' MEASURE("%s:", out_=cls(f)); done(); }'%form) else: print(hdr+"using NetT=%s;"%net) print("volatile uint8_t in_[%d]; volatile uint8_t out_;"%N) - print("int main(){ for(;;){ wave::Features<%d> f; for(int i=0;i<%d;i++) f.v[i]=in_[i]; out_=NetT::proc<0>(f);} }"%(N,N)) + print("int main(){ for(;;){ inp::Bytes60 f; for(int i=0;i<%d;i++) inp::band(f)[i]=in_[i]; out_=NetT::proc<0>(f);} }"%N) PY } D=$(mktemp -d); trap 'rm -rf "$D"' EXIT diff --git a/examples/static_net/measure/rr.cpp b/examples/static_net/measure/rr.cpp index a1976a0..d3e4ae0 100644 --- a/examples/static_net/measure/rr.cpp +++ b/examples/static_net/measure/rr.cpp @@ -1,6 +1,6 @@ #include "harness.h" #include "roll_common.h" volatile uint8_t x[60]; volatile uint8_t out_; -__attribute__((noinline)) bool cls(wave::Features<60>& f){ return Rolled::proc<0>(f); } -int main(){ uinit(); wave::Features<60> f; for(int i=0;i<60;i++) f.v[i]=x[i]^(i*37); +__attribute__((noinline)) bool cls(inp::Bytes60& f){ return Rolled::proc<0>(f); } +int main(){ uinit(); inp::Bytes60 f; for(int i=0;i<60;i++) inp::band(f)[i]=x[i]^(i*37); MEASURE("rr:", out_=cls(f)); done(); } diff --git a/examples/static_net/measure/rs.cpp b/examples/static_net/measure/rs.cpp index 3efd38e..b8c4e84 100644 --- a/examples/static_net/measure/rs.cpp +++ b/examples/static_net/measure/rs.cpp @@ -1,6 +1,6 @@ #include "harness.h" #include "roll_common.h" volatile uint8_t x[60]; volatile uint8_t out_; -__attribute__((noinline)) bool cls(wave::Features<60>& f){ return Sparse::proc<0>(f); } -int main(){ uinit(); wave::Features<60> f; for(int i=0;i<60;i++) f.v[i]=x[i]^(i*37); +__attribute__((noinline)) bool cls(inp::Bytes60& f){ return Sparse::proc<0>(f); } +int main(){ uinit(); inp::Bytes60 f; for(int i=0;i<60;i++) inp::band(f)[i]=x[i]^(i*37); MEASURE("rs:", out_=cls(f)); done(); } diff --git a/examples/static_net/measure/ru.cpp b/examples/static_net/measure/ru.cpp index 49a3a3a..95a0e8e 100644 --- a/examples/static_net/measure/ru.cpp +++ b/examples/static_net/measure/ru.cpp @@ -1,6 +1,6 @@ #include "harness.h" #include "roll_common.h" volatile uint8_t x[60]; volatile uint8_t out_; -__attribute__((noinline)) bool cls(wave::Features<60>& f){ return Unrolled::proc<0>(f); } -int main(){ uinit(); wave::Features<60> f; for(int i=0;i<60;i++) f.v[i]=x[i]^(i*37); +__attribute__((noinline)) bool cls(inp::Bytes60& f){ return Unrolled::proc<0>(f); } +int main(){ uinit(); inp::Bytes60 f; for(int i=0;i<60;i++) inp::band(f)[i]=x[i]^(i*37); MEASURE("ru:", out_=cls(f)); done(); } diff --git a/examples/static_net/measure/sonar_lin.cpp b/examples/static_net/measure/sonar_lin.cpp index 66ee76e..a76ccec 100644 --- a/examples/static_net/measure/sonar_lin.cpp +++ b/examples/static_net/measure/sonar_lin.cpp @@ -1,8 +1,9 @@ #include "harness.h" #include "waveCell.h" +#include "inputs.h" #include "sonar_lin_params.h" volatile uint8_t x[60]; volatile uint8_t out_; -int main(){ uinit(); wave::Features<60> f; for(int i=0;i<60;i++) f.v[i]=x[i]^(i*37); +int main(){ uinit(); inp::Bytes60 f; for(int i=0;i<60;i++) inp::band(f)[i]=x[i]^(i*37); MEASURE("slnarrow:", out_=SonarLinFold0::proc(f)); MEASURE("slwide:", out_=SonarLinFold0Wide::proc(f)); done(); } diff --git a/examples/static_net/models/banknote/net.h b/examples/static_net/models/banknote/net.h index 4b5a757..f3eb76c 100644 --- a/examples/static_net/models/banknote/net.h +++ b/examples/static_net/models/banknote/net.h @@ -1,12 +1,23 @@ #pragma once // The trained Banknote classifier of the running example, as a TYPE: one wave cell of four graded inputs. The trained parameters -// (wave_params.h, generated by train/bn2x.c: fold 1) are template arguments; there is no table and no state. +// (wave_params.h, generated by train/bn2x.c: fold 1) are template arguments; there is no table. Its inputs are the four fields of one +// slot, named as the dataset names them; a Wave reads its field by name. #include "waveCell.h" #include "wave_params.h" + +struct BanknoteTag {}; +struct BanknoteIn { uint8_t variance, skewness, curtosis, entropy; }; +using BanknoteState = hapi::APIOf>::Res; +using Variance = snet::Field; +using Skewness = snet::Field; +using Curtosis = snet::Field; +using Entropy = snet::Field; +inline BanknoteState banknote(const BanknoteIn& in) { return BanknoteState{{}, {in}}; } // banknote({variance, skewness, curtosis, entropy}) + using BanknoteNet=wave::Cell, - wave::Wave<1,WAVE_F1_N,WAVE_F1_S,WAVE_F1_P,WAVE_F1_M>, - wave::Wave<2,WAVE_F2_N,WAVE_F2_S,WAVE_F2_P,WAVE_F2_M>, - wave::Wave<3,WAVE_F3_N,WAVE_F3_S,WAVE_F3_P,WAVE_F3_M> + wave::Wave, + wave::Wave, + wave::Wave, + wave::Wave >; diff --git a/examples/static_net/models/banknote/wave_params.h b/examples/static_net/models/banknote/wave_params.h index fef8bf1..adc0cda 100644 --- a/examples/static_net/models/banknote/wave_params.h +++ b/examples/static_net/models/banknote/wave_params.h @@ -1,22 +1,22 @@ // generated by bn2.c, Banknote 5-fold CV, fold 1 (seed 42): train 99.64% test 100.00% #pragma once #define WAVE_K 175 -#define WAVE_F0_N 0 -#define WAVE_F0_S -2 -#define WAVE_F0_P 110 -#define WAVE_F0_M 0xba -#define WAVE_F1_N 0 -#define WAVE_F1_S -2 -#define WAVE_F1_P 80 -#define WAVE_F1_M 0xbf -#define WAVE_F2_N 0 -#define WAVE_F2_S -2 -#define WAVE_F2_P 0 -#define WAVE_F2_M 0x3f -#define WAVE_F3_N 0 -#define WAVE_F3_S -7 -#define WAVE_F3_P 0 -#define WAVE_F3_M 0x01 -// quantization q=round((x-min)/(max-min)*255), clamped +#define WAVE_VARIANCE_N 0 +#define WAVE_VARIANCE_S -2 +#define WAVE_VARIANCE_P 110 +#define WAVE_VARIANCE_M 0xba +#define WAVE_SKEWNESS_N 0 +#define WAVE_SKEWNESS_S -2 +#define WAVE_SKEWNESS_P 80 +#define WAVE_SKEWNESS_M 0xbf +#define WAVE_CURTOSIS_N 0 +#define WAVE_CURTOSIS_S -2 +#define WAVE_CURTOSIS_P 0 +#define WAVE_CURTOSIS_M 0x3f +#define WAVE_ENTROPY_N 0 +#define WAVE_ENTROPY_S -7 +#define WAVE_ENTROPY_P 0 +#define WAVE_ENTROPY_M 0x01 +// quantization q=round((x-min)/(max-min)*255), clamped; in the order of the features named above static const double WAVE_MIN[4]={-7.0420999999999996,-13.773099999999999,-5.2861000000000002,-8.5481999999999996}; static const double WAVE_MAX[4]={6.8247999999999998,12.7302,17.927399999999999,2.1625000000000001}; diff --git a/examples/static_net/models/banknote/wave_vectors.h b/examples/static_net/models/banknote/wave_vectors.h index 06416c7..4695738 100644 --- a/examples/static_net/models/banknote/wave_vectors.h +++ b/examples/static_net/models/banknote/wave_vectors.h @@ -1,5 +1,11 @@ -// fold-1 held-out rows, quantized with fold-1 train min/max: {q0,q1,q2,q3,label,expected_model_out} +// fold-1 held-out rows, quantized with fold-1 train min/max: {variance,skewness,curtosis,entropy,label,expected_model_out} #pragma once +#define WAVE_COL_VARIANCE 0 +#define WAVE_COL_SKEWNESS 1 +#define WAVE_COL_CURTOSIS 2 +#define WAVE_COL_ENTROPY 3 +#define WAVE_COL_LABEL 4 +#define WAVE_COL_MODEL 5 #define WAVE_NVEC 274 static const unsigned char WAVE_VEC[274][6] WAVE_VEC_ATTR={ {122,132,57,193,1,1}, diff --git a/examples/static_net/models/roll60/roll_common.h b/examples/static_net/models/roll60/roll_common.h index a511204..9abaeef 100644 --- a/examples/static_net/models/roll60/roll_common.h +++ b/examples/static_net/models/roll60/roll_common.h @@ -1,13 +1,14 @@ #include "waveCell.h" #include "roll.h" +#include "inputs.h" struct API32 { template SNET_INLINE static constexpr int32_t proc(const I&) {return 0;} - template SNET_INLINE static constexpr void update(I&) {} }; +}; template struct B32 {template struct Part:O { using Base=O; using Base::Base; template SNET_INLINE static constexpr int32_t proc(const I& in) {return int32_t(b)+Base::proc(in);} };}; struct Pos {template struct Part:O { using Base=O; using Base::Base; template SNET_INLINE static constexpr bool proc(const I& in) {return Base::proc(in)>0;} };}; template using C=hapi::APIOf; -using Unrolled=snet::Net,snet::T<1,18>,snet::T<2,89>,snet::T<3,78>,snet::T<4,68>,snet::T<5,-111>,snet::T<6,-62>,snet::T<7,-97>,snet::T<8,-1>,snet::T<9,67>,snet::T<10,-12>,snet::T<11,-7>,snet::T<12,39>,snet::T<13,-30>,snet::T<14,74>,snet::T<15,-74>,snet::T<16,-103>,snet::T<17,-3>,snet::T<18,-120>,snet::T<19,101>,snet::T<20,86>,snet::T<21,-28>,snet::T<22,-17>,snet::T<23,28>,snet::T<24,68>,snet::T<25,69>,snet::T<26,-127>,snet::T<27,51>,snet::T<28,-13>,snet::T<29,-59>,snet::T<30,57>,snet::T<31,78>,snet::T<32,-69>,snet::T<33,24>,snet::T<34,114>,snet::T<35,-101>,snet::T<36,103>,snet::T<37,-46>,snet::T<38,-120>,snet::T<39,-122>,snet::T<40,-121>,snet::T<41,39>,snet::T<42,11>,snet::T<43,-125>,snet::T<44,113>,snet::T<45,98>,snet::T<46,-30>,snet::T<47,48>,snet::T<48,-72>,snet::T<49,121>,snet::T<50,-19>,snet::T<51,58>,snet::T<52,-120>,snet::T<53,8>,snet::T<54,-71>,snet::T<55,68>,snet::T<56,-15>,snet::T<57,113>,snet::T<58,-1>,snet::T<59,14>,B32<-2000>>>; -using Rolled =snet::Net,snet::T<1,18>,snet::T<2,89>,snet::T<3,78>,snet::T<4,68>,snet::T<5,-111>,snet::T<6,-62>,snet::T<7,-97>,snet::T<8,-1>,snet::T<9,67>,snet::T<10,-12>,snet::T<11,-7>,snet::T<12,39>,snet::T<13,-30>,snet::T<14,74>,snet::T<15,-74>,snet::T<16,-103>,snet::T<17,-3>,snet::T<18,-120>,snet::T<19,101>,snet::T<20,86>,snet::T<21,-28>,snet::T<22,-17>,snet::T<23,28>,snet::T<24,68>,snet::T<25,69>,snet::T<26,-127>,snet::T<27,51>,snet::T<28,-13>,snet::T<29,-59>,snet::T<30,57>,snet::T<31,78>,snet::T<32,-69>,snet::T<33,24>,snet::T<34,114>,snet::T<35,-101>,snet::T<36,103>,snet::T<37,-46>,snet::T<38,-120>,snet::T<39,-122>,snet::T<40,-121>,snet::T<41,39>,snet::T<42,11>,snet::T<43,-125>,snet::T<44,113>,snet::T<45,98>,snet::T<46,-30>,snet::T<47,48>,snet::T<48,-72>,snet::T<49,121>,snet::T<50,-19>,snet::T<51,58>,snet::T<52,-120>,snet::T<53,8>,snet::T<54,-71>,snet::T<55,68>,snet::T<56,-15>,snet::T<57,113>,snet::T<58,-1>,snet::T<59,14>>,B32<-2000>>>; -using Sparse =snet::Net,snet::T<58,-1>,snet::T<57,113>,snet::T<56,-15>,snet::T<55,68>,snet::T<54,-71>,snet::T<53,8>,snet::T<52,-120>,snet::T<51,58>,snet::T<50,-19>,snet::T<49,121>,snet::T<48,-72>,snet::T<47,48>,snet::T<46,-30>,snet::T<45,98>,snet::T<44,113>,snet::T<43,-125>,snet::T<42,11>,snet::T<41,39>,snet::T<40,-121>,snet::T<39,-122>,snet::T<38,-120>,snet::T<37,-46>,snet::T<36,103>,snet::T<35,-101>,snet::T<34,114>,snet::T<33,24>,snet::T<32,-69>,snet::T<31,78>,snet::T<30,57>,snet::T<29,-59>,snet::T<28,-13>,snet::T<27,51>,snet::T<26,-127>,snet::T<25,69>,snet::T<24,68>,snet::T<23,28>,snet::T<22,-17>,snet::T<21,-28>,snet::T<20,86>,snet::T<19,101>,snet::T<18,-120>,snet::T<17,-3>,snet::T<16,-103>,snet::T<15,-74>,snet::T<14,74>,snet::T<13,-30>,snet::T<12,39>,snet::T<11,-7>,snet::T<10,-12>,snet::T<9,67>,snet::T<8,-1>,snet::T<7,-97>,snet::T<6,-62>,snet::T<5,-111>,snet::T<4,68>,snet::T<3,78>,snet::T<2,89>,snet::T<1,18>,snet::T<0,-93>>,B32<-2000>>>; +using Unrolled=snet::Net,-93>,snet::T,18>,snet::T,89>,snet::T,78>,snet::T,68>,snet::T,-111>,snet::T,-62>,snet::T,-97>,snet::T,-1>,snet::T,67>,snet::T,-12>,snet::T,-7>,snet::T,39>,snet::T,-30>,snet::T,74>,snet::T,-74>,snet::T,-103>,snet::T,-3>,snet::T,-120>,snet::T,101>,snet::T,86>,snet::T,-28>,snet::T,-17>,snet::T,28>,snet::T,68>,snet::T,69>,snet::T,-127>,snet::T,51>,snet::T,-13>,snet::T,-59>,snet::T,57>,snet::T,78>,snet::T,-69>,snet::T,24>,snet::T,114>,snet::T,-101>,snet::T,103>,snet::T,-46>,snet::T,-120>,snet::T,-122>,snet::T,-121>,snet::T,39>,snet::T,11>,snet::T,-125>,snet::T,113>,snet::T,98>,snet::T,-30>,snet::T,48>,snet::T,-72>,snet::T,121>,snet::T,-19>,snet::T,58>,snet::T,-120>,snet::T,8>,snet::T,-71>,snet::T,68>,snet::T,-15>,snet::T,113>,snet::T,-1>,snet::T,14>,B32<-2000>>>; +using Rolled =snet::Net,-93>,snet::T,18>,snet::T,89>,snet::T,78>,snet::T,68>,snet::T,-111>,snet::T,-62>,snet::T,-97>,snet::T,-1>,snet::T,67>,snet::T,-12>,snet::T,-7>,snet::T,39>,snet::T,-30>,snet::T,74>,snet::T,-74>,snet::T,-103>,snet::T,-3>,snet::T,-120>,snet::T,101>,snet::T,86>,snet::T,-28>,snet::T,-17>,snet::T,28>,snet::T,68>,snet::T,69>,snet::T,-127>,snet::T,51>,snet::T,-13>,snet::T,-59>,snet::T,57>,snet::T,78>,snet::T,-69>,snet::T,24>,snet::T,114>,snet::T,-101>,snet::T,103>,snet::T,-46>,snet::T,-120>,snet::T,-122>,snet::T,-121>,snet::T,39>,snet::T,11>,snet::T,-125>,snet::T,113>,snet::T,98>,snet::T,-30>,snet::T,48>,snet::T,-72>,snet::T,121>,snet::T,-19>,snet::T,58>,snet::T,-120>,snet::T,8>,snet::T,-71>,snet::T,68>,snet::T,-15>,snet::T,113>,snet::T,-1>,snet::T,14>>,B32<-2000>>>; +using Sparse =snet::Net,14>,snet::T,-1>,snet::T,113>,snet::T,-15>,snet::T,68>,snet::T,-71>,snet::T,8>,snet::T,-120>,snet::T,58>,snet::T,-19>,snet::T,121>,snet::T,-72>,snet::T,48>,snet::T,-30>,snet::T,98>,snet::T,113>,snet::T,-125>,snet::T,11>,snet::T,39>,snet::T,-121>,snet::T,-122>,snet::T,-120>,snet::T,-46>,snet::T,103>,snet::T,-101>,snet::T,114>,snet::T,24>,snet::T,-69>,snet::T,78>,snet::T,57>,snet::T,-59>,snet::T,-13>,snet::T,51>,snet::T,-127>,snet::T,69>,snet::T,68>,snet::T,28>,snet::T,-17>,snet::T,-28>,snet::T,86>,snet::T,101>,snet::T,-120>,snet::T,-3>,snet::T,-103>,snet::T,-74>,snet::T,74>,snet::T,-30>,snet::T,39>,snet::T,-7>,snet::T,-12>,snet::T,67>,snet::T,-1>,snet::T,-97>,snet::T,-62>,snet::T,-111>,snet::T,68>,snet::T,78>,snet::T,89>,snet::T,18>,snet::T,-93>>,B32<-2000>>>; diff --git a/examples/static_net/models/sonar/sonar_lin_params.h b/examples/static_net/models/sonar/sonar_lin_params.h index de14390..c1b6329 100644 --- a/examples/static_net/models/sonar/sonar_lin_params.h +++ b/examples/static_net/models/sonar/sonar_lin_params.h @@ -1,34 +1,35 @@ #pragma once // generated by gen_lin_sonar.py from sonar_lin_train.out -- do not hand-edit #include "linCell.h" +#include "inputs.h" // fold 0: float train 95.78 test 78.57, scale=2.29047 -using SonarLinFold0 = lin::CellOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf>; -using SonarLinFold0Wide = lin::CellOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf>; +using SonarLinFold0 = lin::CellOf, lin::InOf,52>, lin::InOf,-17>, lin::InOf,-75>, lin::InOf,79>, lin::InOf,-23>, lin::InOf,41>, lin::InOf,-84>, lin::InOf,-50>, lin::InOf,54>, lin::InOf,19>, lin::InOf,30>, lin::InOf,73>, lin::InOf,-53>, lin::InOf,25>, lin::InOf,12>, lin::InOf,-10>, lin::InOf,-54>, lin::InOf,51>, lin::InOf,-22>, lin::InOf,15>, lin::InOf,18>, lin::InOf,34>, lin::InOf,-13>, lin::InOf,36>, lin::InOf,24>, lin::InOf,-38>, lin::InOf,22>, lin::InOf,5>, lin::InOf,8>, lin::InOf,53>, lin::InOf,-103>, lin::InOf,47>, lin::InOf,44>, lin::InOf,-48>, lin::InOf,55>, lin::InOf,-43>, lin::InOf,-50>, lin::InOf,15>, lin::InOf,45>, lin::InOf,-60>, lin::InOf,8>, lin::InOf,-28>, lin::InOf,30>, lin::InOf,45>, lin::InOf,19>, lin::InOf,41>, lin::InOf,-11>, lin::InOf,59>, lin::InOf,100>, lin::InOf,-127>, lin::InOf,33>, lin::InOf,58>, lin::InOf,20>, lin::InOf,45>, lin::InOf,12>, lin::InOf,-29>, lin::InOf,-36>, lin::InOf,28>, lin::InOf,-10>, lin::InOf,25>>; +using SonarLinFold0Wide = lin::CellOf, lin::InOf,52>, lin::InOf,-17>, lin::InOf,-75>, lin::InOf,79>, lin::InOf,-23>, lin::InOf,41>, lin::InOf,-84>, lin::InOf,-50>, lin::InOf,54>, lin::InOf,19>, lin::InOf,30>, lin::InOf,73>, lin::InOf,-53>, lin::InOf,25>, lin::InOf,12>, lin::InOf,-10>, lin::InOf,-54>, lin::InOf,51>, lin::InOf,-22>, lin::InOf,15>, lin::InOf,18>, lin::InOf,34>, lin::InOf,-13>, lin::InOf,36>, lin::InOf,24>, lin::InOf,-38>, lin::InOf,22>, lin::InOf,5>, lin::InOf,8>, lin::InOf,53>, lin::InOf,-103>, lin::InOf,47>, lin::InOf,44>, lin::InOf,-48>, lin::InOf,55>, lin::InOf,-43>, lin::InOf,-50>, lin::InOf,15>, lin::InOf,45>, lin::InOf,-60>, lin::InOf,8>, lin::InOf,-28>, lin::InOf,30>, lin::InOf,45>, lin::InOf,19>, lin::InOf,41>, lin::InOf,-11>, lin::InOf,59>, lin::InOf,100>, lin::InOf,-127>, lin::InOf,33>, lin::InOf,58>, lin::InOf,20>, lin::InOf,45>, lin::InOf,12>, lin::InOf,-29>, lin::InOf,-36>, lin::InOf,28>, lin::InOf,-10>, lin::InOf,25>>; #define SONAR_LIN_FOLD0_TRAIN_ACC 95.78313 #define SONAR_LIN_FOLD0_TEST_ACC 78.57143 // fold 1: float train 99.40 test 61.90, scale=2.26342 -using SonarLinFold1 = lin::CellOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf>; -using SonarLinFold1Wide = lin::CellOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf>; +using SonarLinFold1 = lin::CellOf, lin::InOf,18>, lin::InOf,37>, lin::InOf,-29>, lin::InOf,68>, lin::InOf,-12>, lin::InOf,-4>, lin::InOf,-42>, lin::InOf,-46>, lin::InOf,60>, lin::InOf,6>, lin::InOf,28>, lin::InOf,78>, lin::InOf,1>, lin::InOf,-37>, lin::InOf,11>, lin::InOf,-14>, lin::InOf,-51>, lin::InOf,40>, lin::InOf,-19>, lin::InOf,-13>, lin::InOf,11>, lin::InOf,39>, lin::InOf,19>, lin::InOf,6>, lin::InOf,-21>, lin::InOf,13>, lin::InOf,9>, lin::InOf,-23>, lin::InOf,49>, lin::InOf,9>, lin::InOf,-127>, lin::InOf,55>, lin::InOf,26>, lin::InOf,-9>, lin::InOf,-4>, lin::InOf,-52>, lin::InOf,-46>, lin::InOf,34>, lin::InOf,-17>, lin::InOf,-67>, lin::InOf,68>, lin::InOf,-57>, lin::InOf,27>, lin::InOf,41>, lin::InOf,29>, lin::InOf,21>, lin::InOf,-12>, lin::InOf,31>, lin::InOf,69>, lin::InOf,-39>, lin::InOf,4>, lin::InOf,-1>, lin::InOf,-5>, lin::InOf,13>, lin::InOf,-17>, lin::InOf,10>, lin::InOf,1>, lin::InOf,36>, lin::InOf,65>, lin::InOf,-30>>; +using SonarLinFold1Wide = lin::CellOf, lin::InOf,18>, lin::InOf,37>, lin::InOf,-29>, lin::InOf,68>, lin::InOf,-12>, lin::InOf,-4>, lin::InOf,-42>, lin::InOf,-46>, lin::InOf,60>, lin::InOf,6>, lin::InOf,28>, lin::InOf,78>, lin::InOf,1>, lin::InOf,-37>, lin::InOf,11>, lin::InOf,-14>, lin::InOf,-51>, lin::InOf,40>, lin::InOf,-19>, lin::InOf,-13>, lin::InOf,11>, lin::InOf,39>, lin::InOf,19>, lin::InOf,6>, lin::InOf,-21>, lin::InOf,13>, lin::InOf,9>, lin::InOf,-23>, lin::InOf,49>, lin::InOf,9>, lin::InOf,-127>, lin::InOf,55>, lin::InOf,26>, lin::InOf,-9>, lin::InOf,-4>, lin::InOf,-52>, lin::InOf,-46>, lin::InOf,34>, lin::InOf,-17>, lin::InOf,-67>, lin::InOf,68>, lin::InOf,-57>, lin::InOf,27>, lin::InOf,41>, lin::InOf,29>, lin::InOf,21>, lin::InOf,-12>, lin::InOf,31>, lin::InOf,69>, lin::InOf,-39>, lin::InOf,4>, lin::InOf,-1>, lin::InOf,-5>, lin::InOf,13>, lin::InOf,-17>, lin::InOf,10>, lin::InOf,1>, lin::InOf,36>, lin::InOf,65>, lin::InOf,-30>>; #define SONAR_LIN_FOLD1_TRAIN_ACC 99.39759 #define SONAR_LIN_FOLD1_TEST_ACC 61.90476 // fold 2: float train 94.01 test 80.49, scale=2.39286 -using SonarLinFold2 = lin::CellOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf>; -using SonarLinFold2Wide = lin::CellOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf>; +using SonarLinFold2 = lin::CellOf, lin::InOf,36>, lin::InOf,27>, lin::InOf,-75>, lin::InOf,62>, lin::InOf,-26>, lin::InOf,3>, lin::InOf,-49>, lin::InOf,-53>, lin::InOf,33>, lin::InOf,16>, lin::InOf,18>, lin::InOf,97>, lin::InOf,-2>, lin::InOf,-31>, lin::InOf,-7>, lin::InOf,-8>, lin::InOf,-47>, lin::InOf,33>, lin::InOf,-6>, lin::InOf,2>, lin::InOf,19>, lin::InOf,33>, lin::InOf,-12>, lin::InOf,48>, lin::InOf,-6>, lin::InOf,-33>, lin::InOf,24>, lin::InOf,-25>, lin::InOf,3>, lin::InOf,94>, lin::InOf,-127>, lin::InOf,31>, lin::InOf,40>, lin::InOf,-61>, lin::InOf,54>, lin::InOf,-35>, lin::InOf,-65>, lin::InOf,6>, lin::InOf,52>, lin::InOf,-71>, lin::InOf,6>, lin::InOf,21>, lin::InOf,2>, lin::InOf,-2>, lin::InOf,54>, lin::InOf,27>, lin::InOf,-1>, lin::InOf,54>, lin::InOf,91>, lin::InOf,-115>, lin::InOf,61>, lin::InOf,78>, lin::InOf,35>, lin::InOf,33>, lin::InOf,-32>, lin::InOf,-36>, lin::InOf,-3>, lin::InOf,37>, lin::InOf,7>, lin::InOf,35>>; +using SonarLinFold2Wide = lin::CellOf, lin::InOf,36>, lin::InOf,27>, lin::InOf,-75>, lin::InOf,62>, lin::InOf,-26>, lin::InOf,3>, lin::InOf,-49>, lin::InOf,-53>, lin::InOf,33>, lin::InOf,16>, lin::InOf,18>, lin::InOf,97>, lin::InOf,-2>, lin::InOf,-31>, lin::InOf,-7>, lin::InOf,-8>, lin::InOf,-47>, lin::InOf,33>, lin::InOf,-6>, lin::InOf,2>, lin::InOf,19>, lin::InOf,33>, lin::InOf,-12>, lin::InOf,48>, lin::InOf,-6>, lin::InOf,-33>, lin::InOf,24>, lin::InOf,-25>, lin::InOf,3>, lin::InOf,94>, lin::InOf,-127>, lin::InOf,31>, lin::InOf,40>, lin::InOf,-61>, lin::InOf,54>, lin::InOf,-35>, lin::InOf,-65>, lin::InOf,6>, lin::InOf,52>, lin::InOf,-71>, lin::InOf,6>, lin::InOf,21>, lin::InOf,2>, lin::InOf,-2>, lin::InOf,54>, lin::InOf,27>, lin::InOf,-1>, lin::InOf,54>, lin::InOf,91>, lin::InOf,-115>, lin::InOf,61>, lin::InOf,78>, lin::InOf,35>, lin::InOf,33>, lin::InOf,-32>, lin::InOf,-36>, lin::InOf,-3>, lin::InOf,37>, lin::InOf,7>, lin::InOf,35>>; #define SONAR_LIN_FOLD2_TRAIN_ACC 94.01198 #define SONAR_LIN_FOLD2_TEST_ACC 80.48780 // fold 3: float train 99.40 test 66.67, scale=3.8024 -using SonarLinFold3 = lin::CellOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf>; -using SonarLinFold3Wide = lin::CellOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf>; +using SonarLinFold3 = lin::CellOf, lin::InOf,83>, lin::InOf,32>, lin::InOf,-127>, lin::InOf,3>, lin::InOf,35>, lin::InOf,16>, lin::InOf,-48>, lin::InOf,-109>, lin::InOf,39>, lin::InOf,57>, lin::InOf,98>, lin::InOf,61>, lin::InOf,19>, lin::InOf,0>, lin::InOf,30>, lin::InOf,-67>, lin::InOf,-6>, lin::InOf,-63>, lin::InOf,47>, lin::InOf,43>, lin::InOf,-4>, lin::InOf,0>, lin::InOf,36>, lin::InOf,48>, lin::InOf,-15>, lin::InOf,-18>, lin::InOf,-43>, lin::InOf,-4>, lin::InOf,-2>, lin::InOf,73>, lin::InOf,-111>, lin::InOf,46>, lin::InOf,-27>, lin::InOf,-28>, lin::InOf,-1>, lin::InOf,-88>, lin::InOf,-22>, lin::InOf,70>, lin::InOf,34>, lin::InOf,-119>, lin::InOf,-7>, lin::InOf,86>, lin::InOf,44>, lin::InOf,76>, lin::InOf,44>, lin::InOf,-9>, lin::InOf,31>, lin::InOf,61>, lin::InOf,79>, lin::InOf,-125>, lin::InOf,123>, lin::InOf,111>, lin::InOf,5>, lin::InOf,16>, lin::InOf,-42>, lin::InOf,53>, lin::InOf,-100>, lin::InOf,60>, lin::InOf,37>, lin::InOf,5>>; +using SonarLinFold3Wide = lin::CellOf, lin::InOf,83>, lin::InOf,32>, lin::InOf,-127>, lin::InOf,3>, lin::InOf,35>, lin::InOf,16>, lin::InOf,-48>, lin::InOf,-109>, lin::InOf,39>, lin::InOf,57>, lin::InOf,98>, lin::InOf,61>, lin::InOf,19>, lin::InOf,0>, lin::InOf,30>, lin::InOf,-67>, lin::InOf,-6>, lin::InOf,-63>, lin::InOf,47>, lin::InOf,43>, lin::InOf,-4>, lin::InOf,0>, lin::InOf,36>, lin::InOf,48>, lin::InOf,-15>, lin::InOf,-18>, lin::InOf,-43>, lin::InOf,-4>, lin::InOf,-2>, lin::InOf,73>, lin::InOf,-111>, lin::InOf,46>, lin::InOf,-27>, lin::InOf,-28>, lin::InOf,-1>, lin::InOf,-88>, lin::InOf,-22>, lin::InOf,70>, lin::InOf,34>, lin::InOf,-119>, lin::InOf,-7>, lin::InOf,86>, lin::InOf,44>, lin::InOf,76>, lin::InOf,44>, lin::InOf,-9>, lin::InOf,31>, lin::InOf,61>, lin::InOf,79>, lin::InOf,-125>, lin::InOf,123>, lin::InOf,111>, lin::InOf,5>, lin::InOf,16>, lin::InOf,-42>, lin::InOf,53>, lin::InOf,-100>, lin::InOf,60>, lin::InOf,37>, lin::InOf,5>>; #define SONAR_LIN_FOLD3_TRAIN_ACC 99.39759 #define SONAR_LIN_FOLD3_TEST_ACC 66.66667 // fold 4: float train 96.41 test 82.93, scale=2.55523 -using SonarLinFold4 = lin::CellOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf>; -using SonarLinFold4Wide = lin::CellOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf, lin::InOf>; +using SonarLinFold4 = lin::CellOf, lin::InOf,53>, lin::InOf,43>, lin::InOf,-74>, lin::InOf,63>, lin::InOf,-17>, lin::InOf,-7>, lin::InOf,-46>, lin::InOf,-22>, lin::InOf,47>, lin::InOf,-12>, lin::InOf,43>, lin::InOf,49>, lin::InOf,-3>, lin::InOf,-3>, lin::InOf,-18>, lin::InOf,-35>, lin::InOf,-12>, lin::InOf,22>, lin::InOf,13>, lin::InOf,18>, lin::InOf,-23>, lin::InOf,40>, lin::InOf,33>, lin::InOf,9>, lin::InOf,-11>, lin::InOf,-14>, lin::InOf,16>, lin::InOf,-21>, lin::InOf,18>, lin::InOf,67>, lin::InOf,-127>, lin::InOf,55>, lin::InOf,42>, lin::InOf,-53>, lin::InOf,33>, lin::InOf,-48>, lin::InOf,-60>, lin::InOf,5>, lin::InOf,46>, lin::InOf,-52>, lin::InOf,-2>, lin::InOf,-3>, lin::InOf,19>, lin::InOf,17>, lin::InOf,86>, lin::InOf,5>, lin::InOf,10>, lin::InOf,69>, lin::InOf,67>, lin::InOf,-114>, lin::InOf,39>, lin::InOf,58>, lin::InOf,42>, lin::InOf,19>, lin::InOf,8>, lin::InOf,-3>, lin::InOf,-9>, lin::InOf,3>, lin::InOf,4>, lin::InOf,-7>>; +using SonarLinFold4Wide = lin::CellOf, lin::InOf,53>, lin::InOf,43>, lin::InOf,-74>, lin::InOf,63>, lin::InOf,-17>, lin::InOf,-7>, lin::InOf,-46>, lin::InOf,-22>, lin::InOf,47>, lin::InOf,-12>, lin::InOf,43>, lin::InOf,49>, lin::InOf,-3>, lin::InOf,-3>, lin::InOf,-18>, lin::InOf,-35>, lin::InOf,-12>, lin::InOf,22>, lin::InOf,13>, lin::InOf,18>, lin::InOf,-23>, lin::InOf,40>, lin::InOf,33>, lin::InOf,9>, lin::InOf,-11>, lin::InOf,-14>, lin::InOf,16>, lin::InOf,-21>, lin::InOf,18>, lin::InOf,67>, lin::InOf,-127>, lin::InOf,55>, lin::InOf,42>, lin::InOf,-53>, lin::InOf,33>, lin::InOf,-48>, lin::InOf,-60>, lin::InOf,5>, lin::InOf,46>, lin::InOf,-52>, lin::InOf,-2>, lin::InOf,-3>, lin::InOf,19>, lin::InOf,17>, lin::InOf,86>, lin::InOf,5>, lin::InOf,10>, lin::InOf,69>, lin::InOf,67>, lin::InOf,-114>, lin::InOf,39>, lin::InOf,58>, lin::InOf,42>, lin::InOf,19>, lin::InOf,8>, lin::InOf,-3>, lin::InOf,-9>, lin::InOf,3>, lin::InOf,4>, lin::InOf,-7>>; #define SONAR_LIN_FOLD4_TRAIN_ACC 96.40719 #define SONAR_LIN_FOLD4_TEST_ACC 82.92683 diff --git a/examples/static_net/models/sonar/sonar_lin_vectors.h b/examples/static_net/models/sonar/sonar_lin_vectors.h index db7a3ed..1e49792 100644 --- a/examples/static_net/models/sonar/sonar_lin_vectors.h +++ b/examples/static_net/models/sonar/sonar_lin_vectors.h @@ -4,8 +4,11 @@ #ifndef SONAR_LIN_VEC_ATTR #define SONAR_LIN_VEC_ATTR #endif +// the two columns after the 60 bands (band k is column k) +#define SONAR_COL_LABEL 60 +#define SONAR_COL_FLOAT 61 -// row = {60 quantized features, true label, float model's own prediction} +// row = {60 quantized features (band k in column k), true label, float model's own prediction} #define SONAR_LIN_FOLD0_NVEC 42 static const uint8_t SONAR_LIN_FOLD0_VEC[42][62] SONAR_LIN_VEC_ATTR = { {45,87,41,11,107,255,255,198,127,76,85,109,198,175,202,181,84,43,59,99,128,85,23,136,159,191,170,203,205,209,200,133,26,69,127,121,27,51,64,102,75,36,56,43,33,35,33,17,15,49,27,96,64,51,22,89,24,25,56,27,0,0}, @@ -52,7 +55,7 @@ static const uint8_t SONAR_LIN_FOLD0_VEC[42][62] SONAR_LIN_VEC_ATTR = { {146,76,28,97,82,11,57,147,211,237,170,84,54,107,115,115,80,96,130,228,253,90,12,0,54,86,48,130,175,209,98,96,146,212,202,182,187,206,194,164,123,152,148,122,170,166,45,127,100,154,62,164,255,212,116,194,112,48,17,55,1,1}, }; -// row = {60 quantized features, true label, float model's own prediction} +// row = {60 quantized features (band k in column k), true label, float model's own prediction} #define SONAR_LIN_FOLD1_NVEC 42 static const uint8_t SONAR_LIN_FOLD1_VEC[42][62] SONAR_LIN_VEC_ATTR = { {41,23,12,28,44,70,79,94,113,113,96,84,85,40,34,69,87,93,60,43,30,29,39,93,145,181,210,217,230,255,255,218,159,158,172,198,216,186,159,155,120,103,125,163,159,84,52,126,120,70,54,76,97,54,27,12,39,29,18,9,1,0}, @@ -99,7 +102,7 @@ static const uint8_t SONAR_LIN_FOLD1_VEC[42][62] SONAR_LIN_VEC_ATTR = { {31,15,0,5,23,25,15,39,50,34,22,16,30,21,7,22,33,87,68,64,43,49,40,53,13,13,88,160,202,187,140,53,112,117,54,81,115,137,165,145,63,69,59,30,19,13,46,73,41,44,19,77,166,101,130,24,11,26,61,47,0,0}, }; -// row = {60 quantized features, true label, float model's own prediction} +// row = {60 quantized features (band k in column k), true label, float model's own prediction} #define SONAR_LIN_FOLD2_NVEC 41 static const uint8_t SONAR_LIN_FOLD2_VEC[41][62] SONAR_LIN_VEC_ATTR = { {80,51,3,32,14,39,113,81,41,38,30,80,67,60,28,49,56,167,211,207,202,228,246,216,167,65,42,141,144,116,196,206,126,106,139,140,27,91,114,117,65,44,115,87,37,48,62,32,93,197,53,71,138,95,28,45,53,60,41,58,0,1}, @@ -145,7 +148,7 @@ static const uint8_t SONAR_LIN_FOLD2_VEC[41][62] SONAR_LIN_VEC_ATTR = { {108,132,105,87,89,31,55,35,59,78,106,150,184,149,151,183,230,231,221,192,183,130,68,77,53,20,34,41,49,29,64,77,78,114,126,68,37,60,76,50,17,12,26,24,16,19,50,87,99,82,55,117,68,60,88,77,23,57,159,69,1,1}, }; -// row = {60 quantized features, true label, float model's own prediction} +// row = {60 quantized features (band k in column k), true label, float model's own prediction} #define SONAR_LIN_FOLD3_NVEC 42 static const uint8_t SONAR_LIN_FOLD3_VEC[42][62] SONAR_LIN_VEC_ATTR = { {62,17,23,41,54,74,114,82,47,110,80,81,84,30,89,82,52,48,54,93,71,151,143,82,53,131,205,172,177,218,151,93,168,229,199,192,152,121,24,168,243,184,116,80,86,120,106,53,31,145,108,123,101,107,60,28,67,7,51,36,0,0}, @@ -192,7 +195,7 @@ static const uint8_t SONAR_LIN_FOLD3_VEC[42][62] SONAR_LIN_VEC_ATTR = { {65,62,39,24,60,85,78,32,0,15,23,93,47,23,30,39,28,24,37,11,42,0,50,60,0,28,114,174,173,156,183,142,164,230,242,245,205,179,163,186,198,159,129,101,55,28,37,57,80,54,15,30,103,112,43,42,96,37,54,37,0,0}, }; -// row = {60 quantized features, true label, float model's own prediction} +// row = {60 quantized features (band k in column k), true label, float model's own prediction} #define SONAR_LIN_FOLD4_NVEC 41 static const uint8_t SONAR_LIN_FOLD4_VEC[41][62] SONAR_LIN_VEC_ATTR = { {42,40,2,19,25,93,150,64,25,55,87,117,141,109,153,188,206,233,255,239,231,238,187,128,101,71,174,221,228,201,108,21,33,57,74,57,28,44,57,74,37,0,6,30,47,9,32,46,37,73,27,20,11,83,84,34,17,14,103,178,0,0}, diff --git a/examples/static_net/src/main.cpp b/examples/static_net/src/main.cpp index 263e801..29c5190 100644 --- a/examples/static_net/src/main.cpp +++ b/examples/static_net/src/main.cpp @@ -25,10 +25,10 @@ struct Report { int agree, correct; }; static Report classify() { Report rep{0, 0}; for (int r = 0; r < WAVE_NVEC; r++) { - wave::Features<4> f{{ROW(r,0), ROW(r,1), ROW(r,2), ROW(r,3)}}; // the state: four input bytes, the only runtime data + BanknoteState f = banknote({ROW(r,WAVE_COL_VARIANCE), ROW(r,WAVE_COL_SKEWNESS), ROW(r,WAVE_COL_CURTOSIS), ROW(r,WAVE_COL_ENTROPY)}); // the state: four input bytes, the only runtime data const bool y = BanknoteNet::proc(f); // the net, evaluated - rep.agree += (y == bool(ROW(r,5))); // the reference model's output for this row - rep.correct += (y == bool(ROW(r,4))); // the row's label + rep.agree += (y == bool(ROW(r,WAVE_COL_MODEL))); // the reference model's output for this row + rep.correct += (y == bool(ROW(r,WAVE_COL_LABEL))); // the row's label } return rep; } diff --git a/examples/static_net/train/README.md b/examples/static_net/train/README.md index 4357daa..e4424b6 100644 --- a/examples/static_net/train/README.md +++ b/examples/static_net/train/README.md @@ -10,6 +10,8 @@ Training happens on a PC and produces constants; the net is then generated as a `bn2x.c` reproduces the committed `models/banknote/wave_params.h` and `wave_vectors.h` exactly, and the Sonar pipeline reproduces `models/sonar/` exactly. +The exports name what they export, so no consumer maps a feature to a position by hand: `bn2x.c` writes the parameters as `WAVE__N/S/P/M` and the row columns as `WAVE_COL_`, `WAVE_COL_LABEL`, `WAVE_COL_MODEL`, from one list of the four feature names (the column order of `bn.csv`, written down once in `bn2x.c`); `gen_lin_sonar.py` writes each term's source as `inp::Band` (element k of the 60-element input field) and the two trailing row columns as `SONAR_COL_LABEL`, `SONAR_COL_FLOAT`. A name the net expects and the generator no longer emits is a compile error. + Data, unmodified copies from the UCI Machine Learning Repository, cite them if you reuse them: * `bn.csv`: *Banknote Authentication* (Volker Lohweg, 2012), 1372 rows, 4 features from wavelet transforms of banknote images, https://archive.ics.uci.edu/dataset/267/banknote+authentication * `sonar.csv`: *Connectionist Bench (Sonar, Mines vs. Rocks)* (R. Paul Gorman and Terrence J. Sejnowski, 1988), 208 rows, 60 features, https://archive.ics.uci.edu/dataset/151/connectionist+bench+sonar+mines+vs+rocks diff --git a/examples/static_net/train/bn2x.c b/examples/static_net/train/bn2x.c index 55c0460..c5e3335 100644 --- a/examples/static_net/train/bn2x.c +++ b/examples/static_net/train/bn2x.c @@ -4,6 +4,9 @@ #include #include #define NF 4 +// the columns of bn.csv, in order (UCI Banknote Authentication: features of the wavelet-transformed image); the exports below name every feature and column by these +static const char* const FEATURE[NF]={"variance","skewness","curtosis","entropy"}; +static void upper(char*d,const char*s){while(*s)*d++=(char)((*s>='a'&&*s<='z')?*s-32:*s),s++;*d=0;} typedef uint8_t u8; int N; double X[1400][NF]; int Y[1400]; u8 Q[1400][NF]; @@ -90,11 +93,15 @@ int main(){ if(fold==1){FILE*h=fopen("wave_params.h","w"); fprintf(h,"// generated by bn2.c, Banknote 5-fold CV, fold 1 (seed 42): train %.2f%% test %.2f%%\n",100.0*tb/ntr,100.0*eb/nte); fprintf(h,"#pragma once\n#define WAVE_K %d\n",Kb); - for(int j=0;j", "#ifndef SONAR_LIN_VEC_ATTR", "#define SONAR_LIN_VEC_ATTR", "#endif", ""] + "#include ", "#ifndef SONAR_LIN_VEC_ATTR", "#define SONAR_LIN_VEC_ATTR", "#endif", + "// the two columns after the 60 bands (band k is column k)", "#define SONAR_COL_LABEL 60", "#define SONAR_COL_FLOAT 61", ""] for fd in folds: n = fd["fold"] @@ -56,18 +57,18 @@ def main(): # only the running sum needs the wider type. This is the recommended # form -- see the README for the measured AVR cost of the naive # int32-product alternative kept below for direct comparison. - terms16 = ", ".join(f"lin::InOf" for j in range(60)) + terms16 = ", ".join(f"lin::InOf,{wq[j]}>" for j in range(60)) params.append(f"// fold {n}: float train {fd['train_acc']:.2f} test {fd['test_acc']:.2f}, scale={scale:.6g}") params.append(f"using SonarLinFold{n} = lin::CellOf, {terms16}>;") # naive form: product computed at the full int32_t accumulator width, # kept only as a comparison point (README). - terms32 = ", ".join(f"lin::InOf" for j in range(60)) + terms32 = ", ".join(f"lin::InOf,{wq[j]}>" for j in range(60)) params.append(f"using SonarLinFold{n}Wide = lin::CellOf, {terms32}>;") params.append(f"#define SONAR_LIN_FOLD{n}_TRAIN_ACC {fd['train_acc']:.5f}") params.append(f"#define SONAR_LIN_FOLD{n}_TEST_ACC {fd['test_acc']:.5f}") params.append("") - vectors.append(f"// row = {{60 quantized features, true label, float model's own prediction}}") + vectors.append(f"// row = {{60 quantized features (band k in column k), true label, float model's own prediction}}") vectors.append(f"#define SONAR_LIN_FOLD{n}_NVEC {fd['nte']}") vectors.append(f"static const uint8_t SONAR_LIN_FOLD{n}_VEC[{fd['nte']}][62] SONAR_LIN_VEC_ATTR = {{") for r in fd["rows"]: