memlnaut-nisps/nisps-core/include/nisps/iml.hpp
w1n5t0n d0ba1faaea feat(nisps-core,vcv): complete Phase 0 + Phase 1
Phase 0 — spread-aware API ported to nisps-core C++:
- MLP::DrawWeightsSpread(T spread) — interpolate uniform↔Xavier per layer
- MLP::MoveWeightsSpread(T speed, T spread) — per-layer noise + weight decay
- IML::randomise_weights(Float spread) and IML::move_weights(speed, spread)
- 5 unit tests (10/10 total pass)

Phase 1 — VCV Rack 2 plugin skeleton:
- Makefile with C++20, nisps-core include path
- plugin.json manifest
- Empty MEMLNaut module: 2 inputs, 12 outputs, placeholder SVG panel
- static_assert verifies nisps-core headers resolve
- C++20 confirmed working in VCV SDK (8 existing plugins use it)
2026-03-28 00:36:46 +02:00

91 lines
2.4 KiB
C++

#ifndef NISPS_IML_HPP
#define NISPS_IML_HPP
#include "mlp.hpp"
#include "dataset.hpp"
#include <vector>
#include <cstddef>
#include <functional>
namespace nisps {
template<typename Float = float>
class IML {
public:
enum class Mode { Inference, Training };
using LogFn = void(*)(const char*);
IML(size_t n_inputs, size_t n_outputs,
std::vector<size_t> hidden_layers = {10, 10, 14},
size_t max_iterations = 1000,
Float learning_rate = 1.0f,
Float convergence_threshold = 0.00001f);
// Input
void set_input(size_t index, Float value);
void set_inputs(const Float* values, size_t count);
// Output (valid after process())
const Float* get_outputs() const;
size_t num_inputs() const { return n_inputs_; }
size_t num_outputs() const { return n_outputs_; }
// Set outputs directly (for programmatic training without hardware)
void set_output(size_t index, Float value);
void set_outputs(const Float* values, size_t count);
// Runtime
void process();
// Training workflow
void set_mode(Mode mode);
Mode get_mode() const { return mode_; }
void save_example();
void add_example(const Float* inputs, size_t n_in, const Float* outputs, size_t n_out);
void clear_dataset();
void randomise_weights();
// Spread-aware weight randomization
// spread: 0 = uniform [-1,1], 1 = Xavier-scaled per layer
void randomise_weights(Float spread);
// Spread-aware weight perturbation (for RL exploration)
// speed: noise magnitude, spread: 0 = flat noise, 1 = Xavier-scaled + weight decay
void move_weights(Float speed, Float spread);
// Optional logging
void set_logger(LogFn fn) { log_fn_ = fn; }
private:
void log(const char* msg) const {
if (log_fn_) log_fn_(msg);
}
void train();
size_t n_inputs_;
size_t n_outputs_;
size_t max_iterations_;
Float learning_rate_;
Float convergence_threshold_;
Mode mode_ = Mode::Inference;
bool input_updated_ = false;
bool perform_inference_ = true;
std::vector<Float> input_state_;
std::vector<Float> output_state_;
std::unique_ptr<Dataset> dataset_;
std::unique_ptr<MLP<Float>> mlp_;
typename MLP<Float>::mlp_weights stored_weights_;
bool weights_randomised_ = false;
LogFn log_fn_ = nullptr;
};
} // namespace nisps
#include "iml_impl.hpp"
#endif // NISPS_IML_HPP