You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# Install maturin
pip install maturin
# Clone and install
git clone <repo-url>cd GlassBoxAI-MLP
# Build with all GPU backends
maturin develop --release --features python,cuda,opencl
# Or CPU-only (no GPU dependencies)
maturin develop --release --features python
Using Makefile
# See all available commands
make help# Build and install Python package with all backends
make install
# Run tests
make test# Run examples
make run-xor
make run-backends
Quick Install (Node.js)
# Install napi-rs CLI
npm install -g @napi-rs/cli
# Clone and install
git clone <repo-url>cd GlassBoxAI-MLP
# Build with all GPU backends
npm run build
# Or CPU-only (no GPU dependencies)
npm run build:cpu
Feature Flags
Feature
Description
cuda
Enable CUDA support
opencl
Enable OpenCL support
cli
Build command-line interface
python
Build Python bindings
nodejs
Build Node.js bindings
julia
Build Julia FFI (C API)
# Python: CUDA only
maturin develop --release --features python,cuda
# Python: OpenCL only
maturin develop --release --features python,opencl
# Python: Both CUDA and OpenCL
maturin develop --release --features python,cuda,opencl
# Node.js: All backends
npm run build
# Node.js: CPU only
npm run build:cpu
# C++/Julia: Build with C API
cargo build --release --features julia,cuda,opencl
const{ loadCsv, normalize }=require('facaded-mlp-cuda');// Load dataset from CSVconst{ inputs, targets }=loadCsv('data.csv',4,1);// Normalize inputs to [0, 1] rangeconstnormalized=normalize(inputs);
Complete Example
const{MLP, JsActivationType, JsOptimizerType }=require('facaded-mlp-cuda');// Check available backendsconsole.log('Available GPU backends:',MLP.availableBackends());// Create MLP for XOR problemconstmlp=newMLP(2,[8],1,{hiddenActivation: JsActivationType.Sigmoid,outputActivation: JsActivationType.Sigmoid,gpuBackend: 'auto',});// Set hyperparametersmlp.learningRate=0.5;mlp.optimizer=JsOptimizerType.Adam;mlp.beta1=0.9;mlp.beta2=0.999;mlp.dropoutRate=0.0;mlp.l2Lambda=0.0;console.log(`Created model: ${mlp.toString()}`);console.log(`Using backend: ${mlp.gpuBackend}`);// XOR training dataconstX=[[0,0],[0,1],[1,0],[1,1]];consty=[[0],[1],[1],[0]];// Train with advanced optionsconstresult=mlp.fit(X,y,{epochs: 2000,batchSize: 4,verbose: true,lrDecay: true,lrDecayRate: 0.95,lrDecayEpochs: 100,earlyStop: true,patience: 50});console.log(`Final loss: ${result.finalLoss.toFixed(6)}`);// Predictionsconstpredictions=mlp.predictBatch(X);for(leti=0;i<X.length;i++){console.log(`Input: [${X[i]}] -> Target: ${y[i][0]}, Prediction: ${predictions[i][0].toFixed(4)}`);}// Deep introspection (Facade pattern)console.log('\n--- Deep Introspection ---');// Get specific weightconstweight=mlp.getNeuronWeight(1,0,0);console.log(`Layer 1, Neuron 0, Weight 0: ${weight.toFixed(6)}`);// Get all weights for a neuronconstweights=mlp.getNeuronWeights(1,0);console.log(`Layer 1, Neuron 0 all weights: ${weights}`);// Get biasconstbias=mlp.getNeuronBias(1,0);console.log(`Layer 1, Neuron 0 bias: ${bias.toFixed(6)}`);// Set a weightmlp.setNeuronWeight(1,0,0,0.5);console.log('Set Layer 1, Neuron 0, Weight 0 to 0.5');// Get layer outputs (requires forward pass first)constoutput=mlp.predict([1.0,0.0]);// Run forward passconstlayerOutputs=mlp.getLayerOutputs(0);console.log(`Hidden layer outputs: ${layerOutputs}`);// Get optimizer state for AdamconstoptimizerState=mlp.getOptimizerState(1,0);console.log(`Optimizer state (M, V): ${JSON.stringify(optimizerState)}`);// Get activation histogramconsthistogram=mlp.getActivationHistogram(1,10);console.log(`Activation histogram: ${histogram}`);// Get layer infoconstlayerInfo=mlp.getLayerInfo(1);console.log(`Layer 1 info: ${JSON.stringify(layerInfo)}`);// Save modelmlp.save('xor_model.json');// Load and testconstmlp2=MLP.load('xor_model.json');constoutput2=mlp2.predict([1.0,0.0]);console.log(`\nLoaded model prediction: ${output2[0].toFixed(4)}`);// Feature importance (GlassBox interpretability)constimportance=mlp.featureImportance();console.log('\nFeature importance:');for(const{ featureIndex, score }ofimportance){console.log(` Feature ${featureIndex}: ${score.toFixed(6)}`);}// Export to ONNXmlp.exportOnnx('xor_model.onnx');console.log('\nModel exported to ONNX format');// Import from ONNXconstmlp3=MLP.importOnnx('xor_model.onnx');console.log('Model imported from ONNX format');
TypeScript Support
The package includes full TypeScript definitions in index.d.ts:
structFeatureImportance {
int index;
double score;
};
structLayerInfo {
int size;
Activation activation;
};
structOptimizerState {
std::vector<double> m; // First moment (Adam/RMSProp)
std::vector<double> v; // Second moment (Adam/RMSProp)
};
#include"facaded_mlp.hpp"
#include<iostream>
#include<iomanip>intmain() {
usingnamespacefacaded;// Check available backendsauto backends = MLP::available_backends();
std::cout << "Available backends: ";
for (constauto& backend : backends) {
std::cout << backend << "";
}
std::cout << std::endl;
// Create MLP with custom options
MLPOptions opts;
opts.hidden_activation = Activation::Sigmoid;
opts.output_activation = Activation::Sigmoid;
opts.backend = "auto";
opts.learning_rate = 0.5;
opts.optimizer = Optimizer::Adam;
opts.beta1 = 0.9;
opts.beta2 = 0.999;
MLPmlp(2, {8}, 1, opts);
std::cout << "Created model: " << mlp << std::endl;
std::cout << "Using backend: " << mlp.backend() << std::endl;
// XOR training data
std::vector<std::vector<double>> X = {
{0.0, 0.0}, {0.0, 1.0}, {1.0, 0.0}, {1.0, 1.0}
};
std::vector<std::vector<double>> y = {
{0.0}, {1.0}, {1.0}, {0.0}
};
// Trainauto result = mlp.fit(X, y, 2000, true);
std::cout << std::fixed << std::setprecision(6);
std::cout << "Final loss: " << result.final_loss << std::endl;
// Predictions
std::cout << "\nPredictions:" << std::endl;
for (size_t i = 0; i < X.size(); ++i) {
auto pred = mlp.predict(X[i]);
std::cout << "Input: [" << X[i][0] << ", " << X[i][1] << "] -> "
<< "Target: " << y[i][0] << ", "
<< "Prediction: " << pred[0] << std::endl;
}
// Deep introspection (Facade)
std::cout << "\n--- Deep Introspection ---" << std::endl;
// Get specific weightdouble weight = mlp.get_neuron_weight(1, 0, 0);
std::cout << "Layer 1, Neuron 0, Weight 0: " << weight << std::endl;
// Get all weights for a neuronauto weights = mlp.get_neuron_weights(1, 0);
std::cout << "Layer 1, Neuron 0 all weights: [";
for (size_t i = 0; i < weights.size(); ++i) {
std::cout << weights[i];
if (i < weights.size() - 1) std::cout << ", ";
}
std::cout << "]" << std::endl;
// Get biasdouble bias = mlp.get_neuron_bias(1, 0);
std::cout << "Layer 1, Neuron 0 bias: " << bias << std::endl;
// Get optimizer stateauto opt_state = mlp.get_optimizer_state(1, 0);
std::cout << "Optimizer state (M size, V size): ("
<< opt_state.m.size() << ", " << opt_state.v.size() << ")"
<< std::endl;
// Save model
mlp.save("xor_model.json");
std::cout << "\nModel saved to xor_model.json" << std::endl;
// Load and testauto mlp2 = MLP::load("xor_model.json");
auto output = mlp2.predict({1.0, 0.0});
std::cout << "Loaded model prediction: " << output[0] << std::endl;
// Feature importanceauto importance = mlp.feature_importance();
std::cout << "\nFeature importance:" << std::endl;
for (constauto& fi : importance) {
std::cout << " Feature " << fi.index << ": " << fi.score << std::endl;
}
// Export to ONNX
mlp.export_onnx("xor_model.onnx");
std::cout << "\nModel exported to ONNX format" << std::endl;
return0;
}
CMake Integration
# Find the installed libraryfind_package(facaded_mlpREQUIRED)
# Link against your targettarget_link_libraries(your_targetPRIVATEfacaded::facaded_mlp)
# Or add as subdirectoryadd_subdirectory(path/to/GlassBoxAI-MLP/cpp)
target_link_libraries(your_targetPRIVATEfacaded_mlp)
C API
For C interop or when you need a C-compatible interface, include facaded_mlp.h:
# Install test dependencies
pip install pytest numpy
# Run all tests
pytest tests/ -v
# Run specific test
pytest tests/test_mlp.py::test_xor_training -v
# Run with coverage
pytest tests/ --cov=facaded_mlp_cuda --cov-report=html
Running Node.js Tests
# Run examples as tests
npm test# Or run directly
node examples/xor_example.js
node examples/gpu_backend_example.js
Running C++ Tests
cd cpp/build
# Run example
./xor_example
# Or compile and run directlycd cpp
g++ -std=c++17 -O2 -I include examples/xor_example.cpp \
-L ../target/release -lfacaded_mlp_cuda \
-Wl,-rpath,../target/release \
-o xor_example
./xor_example
Running Julia Tests
cd julia
# Run test suite
julia --project=. -e 'using Pkg; Pkg.test()'# Or run examples interactively
julia --project=.
julia>include("examples/xor_example.jl")
Using Makefile
# Run all tests
make test# Run Python tests only
make test-python
# Run Node.js examples
make test-node
Test Categories
Each test suite covers:
Category
Tests
Help & Usage
Command-line interface verification
Model Creation
Various architecture configurations, backend selection
The Rust implementation includes Kani formal verification proofs that mathematically prove the absence of certain classes of bugs. This goes beyond traditional testing to provide mathematical guarantees about code correctness.
Running Kani Verification
cd kani
# Run all proofs
cargo kani
# Run specific proof
cargo kani --harness proof_name
# Run unit tests
cargo test# Verify specific modules
cargo kani --harness verify_weight_indexing
cargo kani --harness verify_layer_access
cargo kani --harness verify_activation_bounds
Verified Properties
The Kani proofs verify:
Property
Description
Memory Safety
No buffer overflows, null pointer dereferences, or use-after-free
Array Bounds
All array accesses within valid bounds
Integer Overflow
No arithmetic overflows in critical computations
Layer Indexing
Valid layer indices for all operations
Weight/Bias Access
Safe neuron weight and bias indexing
Activation Computation
Activation functions produce valid outputs
No Panics
Critical paths proven panic-free
Why Formal Verification Matters
Traditional testing can only verify specific test cases. Formal verification with Kani:
Exhaustively checks all possible inputs within defined bounds
Mathematically proves absence of panics, buffer overflows, and undefined behavior
Catches edge cases that random testing might miss (e.g., boundary conditions, integer overflow)
Provides cryptographic-level assurance for safety-critical code
Complements traditional testing by proving properties that tests can only sample
Bounds checking (Verified array access with proofs)
Input validation (CLI, Python API, Node.js API argument parsing)
No unsafe code in critical paths (Isolated to GPU FFI boundaries)
Documentation (Inline docs + comprehensive README + API docs)
Version control (Git with semantic versioning)
License clarity (MIT License)
Dependency management (Cargo.lock for reproducible builds)
Supply chain security (Audited dependencies)
Security Features
Feature
Description
Type Safety
Strong typing prevents type confusion vulnerabilities
Lifetime Safety
Rust lifetimes prevent dangling pointers
Thread Safety
Send/Sync traits ensure safe concurrency
Error Handling
Result types force explicit error handling
Panic Safety
Critical sections proven panic-free via Kani
FFI Safety
Minimal unsafe boundaries with thorough validation
Attestation
This codebase has been developed following secure software development lifecycle (SSDLC) practices and demonstrates:
Comprehensive test suites across all implementations (Python, Node.js, CLI, Rust)
Zero warnings compilation across all implementations
Formal verification of critical safety properties
Consistent API across all language/backend combinations
Production-ready code quality with extensive documentation
Security-first design with defense in depth
License
MIT License
Copyright (c) 2025 Matthew Abbott
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.