@oxide-js/spiking 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/examples/demo.ts +101 -0
- package/index.d.ts +19 -0
- package/index.js +316 -0
- package/package.json +47 -0
- package/src/index.ts +5 -0
- package/src/layers/SpikingDense.ts +237 -0
- package/src/layers/SpikingEmbedding.ts +227 -0
- package/src/math/dotProductAddOnly.ts +229 -0
- package/src/models/SpikingSentenceEmbedder.ts +135 -0
- package/src/native_backend.ts +90 -0
- package/src-rust/Cargo.lock +324 -0
- package/src-rust/Cargo.toml +17 -0
- package/src-rust/build.rs +5 -0
- package/src-rust/src/lib.rs +462 -0
- package/test/test_embedding.ts +126 -0
- package/test/test_xor.ts +122 -0
- package/tsconfig.json +9 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# @oxide-js/spiking
|
|
2
|
+
|
|
3
|
+
## 1.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 7db4802: Spiking Neural Networks (SNN) & JSON Compression
|
|
8
|
+
|
|
9
|
+
- Added new `@oxide-js/spiking` package for Biomimetic AI, featuring LIF dynamics and Hebbian Contrastive Learning.
|
|
10
|
+
- Optimized `BaseModel.serialize()` and `setWeights()` in `@oxide-js/models` to compress Float32Array into regular arrays, achieving up to 75% JSON size reductions.
|
|
11
|
+
- Added `mj.argmax` and `mj.threshold` primitives in `@oxide-js/core`.
|
|
12
|
+
- Included `"threshold"` activation typing inside `ActivationType`.
|
package/examples/demo.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { SpikingNetwork } from "../src/core/SpikingNetwork.js";
|
|
2
|
+
import { STDP } from "../src/learning/STDP.js";
|
|
3
|
+
import { PoissonEncoder } from "../src/encoding/PoissonEncoder.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Simulasi Pengenalan Pola Sederhana menggunakan SNN
|
|
7
|
+
* --------------------------------------------------
|
|
8
|
+
* 1. Kita memiliki 3 neuron Input dan 1 neuron Output (Total 4 Neuron)
|
|
9
|
+
* 2. Input merepresentasikan intensitas sinyal (misalnya: [0.9, 0.1, 0.8])
|
|
10
|
+
* 3. Neuron Input terhubung ke Neuron Output
|
|
11
|
+
* 4. STDP akan mengamati dan memperkuat bobot dari input yang sering "menyala" (0.9 dan 0.8)
|
|
12
|
+
*/
|
|
13
|
+
async function runDemo() {
|
|
14
|
+
console.log("=== Memulai Simulasi SNN Add-Only ===\n");
|
|
15
|
+
|
|
16
|
+
// Konfigurasi
|
|
17
|
+
const NUM_INPUTS = 3;
|
|
18
|
+
const NUM_OUTPUTS = 1;
|
|
19
|
+
const TOTAL_NEURONS = NUM_INPUTS + NUM_OUTPUTS;
|
|
20
|
+
const TIME_STEPS = 100;
|
|
21
|
+
|
|
22
|
+
// 1. Inisialisasi Jaringan & Komponen
|
|
23
|
+
// Threshold di-set rendah agar output mudah menembakkan spike
|
|
24
|
+
const net = new SpikingNetwork(TOTAL_NEURONS, 0.8, 2.0);
|
|
25
|
+
const stdp = new STDP(net, {
|
|
26
|
+
learningRate: 0.05,
|
|
27
|
+
aPlus: 1.5,
|
|
28
|
+
aMinus: 0.5, // LTD diturunkan agar sinyal yang sering aktif (berkorelasi kuat) membesar
|
|
29
|
+
wMax: 10.0,
|
|
30
|
+
wMin: 0.0 // Bobot tidak boleh negatif dalam contoh ini
|
|
31
|
+
});
|
|
32
|
+
const encoder = new PoissonEncoder(1.0);
|
|
33
|
+
|
|
34
|
+
// Neuron Output berada di indeks ke-3 (karena 0,1,2 adalah input)
|
|
35
|
+
const OUTPUT_NEURON = 3;
|
|
36
|
+
|
|
37
|
+
// 2. Hubungkan Input ke Output dengan bobot awal yang seragam (kecil)
|
|
38
|
+
console.log("Membangun koneksi awal:");
|
|
39
|
+
for (let i = 0; i < NUM_INPUTS; i++) {
|
|
40
|
+
net.connect(i, OUTPUT_NEURON, 1.0);
|
|
41
|
+
console.log(`- Input Neuron ${i} -> Output Neuron ${OUTPUT_NEURON} (Bobot Awal: 1.0)`);
|
|
42
|
+
}
|
|
43
|
+
console.log("\n");
|
|
44
|
+
|
|
45
|
+
// 3. Menyiapkan Pola Input
|
|
46
|
+
// Neuron 0 (Sinyal Kuat), Neuron 1 (Sinyal Lemah), Neuron 2 (Sinyal Kuat)
|
|
47
|
+
const inputPattern = [0.9, 0.1, 0.8];
|
|
48
|
+
|
|
49
|
+
let totalOutputSpikes = 0;
|
|
50
|
+
|
|
51
|
+
console.log(`Menjalankan simulasi selama ${TIME_STEPS} time-steps...`);
|
|
52
|
+
|
|
53
|
+
for (let t = 0; t < TIME_STEPS; t++) {
|
|
54
|
+
// A. Encode sinyal input kontinu menjadi Spike
|
|
55
|
+
const currentSpikes = encoder.encodeArray(inputPattern);
|
|
56
|
+
|
|
57
|
+
// B. Injeksi spike input secara langsung ke neuron input
|
|
58
|
+
// (Beri potensial yang cukup agar mereka seketika menembakkan spike di step ini)
|
|
59
|
+
for (let i = 0; i < NUM_INPUTS; i++) {
|
|
60
|
+
if (currentSpikes[i] === 1) {
|
|
61
|
+
// Injeksi arus yang jauh di atas threshold (2.0) agar pasti spike
|
|
62
|
+
net.injectCurrent(i, 10.0);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// C. Evaluasi Jaringan (Add-Only Propagation)
|
|
67
|
+
net.step();
|
|
68
|
+
|
|
69
|
+
// D. Hitung Spike Output
|
|
70
|
+
if (net.spikes[OUTPUT_NEURON] === 1) {
|
|
71
|
+
totalOutputSpikes++;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// E. Lakukan Proses Pembelajaran (Plasticity)
|
|
75
|
+
stdp.updateWeights();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 4. Hasil Simulasi
|
|
79
|
+
console.log("\n=== Hasil Simulasi ===");
|
|
80
|
+
console.log(`Total tembakan (spikes) dari Neuron Output: ${totalOutputSpikes}`);
|
|
81
|
+
console.log("\nPerubahan Bobot Akhir (Setelah proses Belajar STDP):");
|
|
82
|
+
|
|
83
|
+
for (let i = 0; i < NUM_INPUTS; i++) {
|
|
84
|
+
// Bobot ke-0 dari array koneksi neuron input 'i'
|
|
85
|
+
const finalWeight = net.weights[i][0];
|
|
86
|
+
const initialInput = inputPattern[i];
|
|
87
|
+
|
|
88
|
+
let status = "";
|
|
89
|
+
if (finalWeight > 1.0) status = "📈 Diperkuat (LTP)";
|
|
90
|
+
else if (finalWeight < 1.0) status = "📉 Diperlemah (LTD)";
|
|
91
|
+
else status = "âž– Tetap";
|
|
92
|
+
|
|
93
|
+
console.log(`Neuron ${i} (Intensitas Sinyal: ${initialInput}) -> Bobot Akhir: ${finalWeight.toFixed(4)} ${status}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.log("\nKesimpulan:");
|
|
97
|
+
console.log("Seperti yang terlihat, SNN secara otomatis mengenali dan memperkuat koneksi dari neuron input yang aktif (Intensitas 0.9 & 0.8),");
|
|
98
|
+
console.log("sementara neuron yang jarang aktif (Intensitas 0.1) bobotnya melemah secara natural melalui aturan STDP.");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
runDemo().catch(console.error);
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/* auto-generated by NAPI-RS */
|
|
5
|
+
|
|
6
|
+
export declare function dotProductAddOnlyNative(aData: Float32Array, aRowsOrig: number, aColsOrig: number, bData: Float32Array, bRowsOrig: number, bColsOrig: number, transA: boolean, transB: boolean, outData: Float32Array): void
|
|
7
|
+
export declare class NativeSpikingNetwork {
|
|
8
|
+
constructor(numNeurons: number, beta: number, defaultThreshold: number)
|
|
9
|
+
connect(pre: number, post: number, weight: number): void
|
|
10
|
+
injectCurrent(neuronIdx: number, current: number): void
|
|
11
|
+
inhibitRange(startIdx: number, endIdx: number, exceptIdx: number, current: number): void
|
|
12
|
+
step(): void
|
|
13
|
+
resetState(): void
|
|
14
|
+
getSpikes(): Array<number>
|
|
15
|
+
getPotentials(): Array<number>
|
|
16
|
+
updateStdp(learningRate: number, tauPlus: number, tauMinus: number, aPlus: number, aMinus: number, wMax: number, wMin: number): void
|
|
17
|
+
saveToFile(filepath: string): void
|
|
18
|
+
loadFromFile(filepath: string): void
|
|
19
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/* prettier-ignore */
|
|
4
|
+
|
|
5
|
+
/* auto-generated by NAPI-RS */
|
|
6
|
+
|
|
7
|
+
const { existsSync, readFileSync } = require('fs')
|
|
8
|
+
const { join } = require('path')
|
|
9
|
+
|
|
10
|
+
const { platform, arch } = process
|
|
11
|
+
|
|
12
|
+
let nativeBinding = null
|
|
13
|
+
let localFileExisted = false
|
|
14
|
+
let loadError = null
|
|
15
|
+
|
|
16
|
+
function isMusl() {
|
|
17
|
+
// For Node 10
|
|
18
|
+
if (!process.report || typeof process.report.getReport !== 'function') {
|
|
19
|
+
try {
|
|
20
|
+
const lddPath = require('child_process').execSync('which ldd').toString().trim()
|
|
21
|
+
return readFileSync(lddPath, 'utf8').includes('musl')
|
|
22
|
+
} catch (e) {
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
const { glibcVersionRuntime } = process.report.getReport().header
|
|
27
|
+
return !glibcVersionRuntime
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
switch (platform) {
|
|
32
|
+
case 'android':
|
|
33
|
+
switch (arch) {
|
|
34
|
+
case 'arm64':
|
|
35
|
+
localFileExisted = existsSync(join(__dirname, 'spiking-native.android-arm64.node'))
|
|
36
|
+
try {
|
|
37
|
+
if (localFileExisted) {
|
|
38
|
+
nativeBinding = require('./spiking-native.android-arm64.node')
|
|
39
|
+
} else {
|
|
40
|
+
nativeBinding = require('@oxide-js/spiking-android-arm64')
|
|
41
|
+
}
|
|
42
|
+
} catch (e) {
|
|
43
|
+
loadError = e
|
|
44
|
+
}
|
|
45
|
+
break
|
|
46
|
+
case 'arm':
|
|
47
|
+
localFileExisted = existsSync(join(__dirname, 'spiking-native.android-arm-eabi.node'))
|
|
48
|
+
try {
|
|
49
|
+
if (localFileExisted) {
|
|
50
|
+
nativeBinding = require('./spiking-native.android-arm-eabi.node')
|
|
51
|
+
} else {
|
|
52
|
+
nativeBinding = require('@oxide-js/spiking-android-arm-eabi')
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
loadError = e
|
|
56
|
+
}
|
|
57
|
+
break
|
|
58
|
+
default:
|
|
59
|
+
throw new Error(`Unsupported architecture on Android ${arch}`)
|
|
60
|
+
}
|
|
61
|
+
break
|
|
62
|
+
case 'win32':
|
|
63
|
+
switch (arch) {
|
|
64
|
+
case 'x64':
|
|
65
|
+
localFileExisted = existsSync(
|
|
66
|
+
join(__dirname, 'spiking-native.win32-x64-msvc.node')
|
|
67
|
+
)
|
|
68
|
+
try {
|
|
69
|
+
if (localFileExisted) {
|
|
70
|
+
nativeBinding = require('./spiking-native.win32-x64-msvc.node')
|
|
71
|
+
} else {
|
|
72
|
+
nativeBinding = require('@oxide-js/spiking-win32-x64-msvc')
|
|
73
|
+
}
|
|
74
|
+
} catch (e) {
|
|
75
|
+
loadError = e
|
|
76
|
+
}
|
|
77
|
+
break
|
|
78
|
+
case 'ia32':
|
|
79
|
+
localFileExisted = existsSync(
|
|
80
|
+
join(__dirname, 'spiking-native.win32-ia32-msvc.node')
|
|
81
|
+
)
|
|
82
|
+
try {
|
|
83
|
+
if (localFileExisted) {
|
|
84
|
+
nativeBinding = require('./spiking-native.win32-ia32-msvc.node')
|
|
85
|
+
} else {
|
|
86
|
+
nativeBinding = require('@oxide-js/spiking-win32-ia32-msvc')
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
loadError = e
|
|
90
|
+
}
|
|
91
|
+
break
|
|
92
|
+
case 'arm64':
|
|
93
|
+
localFileExisted = existsSync(
|
|
94
|
+
join(__dirname, 'spiking-native.win32-arm64-msvc.node')
|
|
95
|
+
)
|
|
96
|
+
try {
|
|
97
|
+
if (localFileExisted) {
|
|
98
|
+
nativeBinding = require('./spiking-native.win32-arm64-msvc.node')
|
|
99
|
+
} else {
|
|
100
|
+
nativeBinding = require('@oxide-js/spiking-win32-arm64-msvc')
|
|
101
|
+
}
|
|
102
|
+
} catch (e) {
|
|
103
|
+
loadError = e
|
|
104
|
+
}
|
|
105
|
+
break
|
|
106
|
+
default:
|
|
107
|
+
throw new Error(`Unsupported architecture on Windows: ${arch}`)
|
|
108
|
+
}
|
|
109
|
+
break
|
|
110
|
+
case 'darwin':
|
|
111
|
+
localFileExisted = existsSync(join(__dirname, 'spiking-native.darwin-universal.node'))
|
|
112
|
+
try {
|
|
113
|
+
if (localFileExisted) {
|
|
114
|
+
nativeBinding = require('./spiking-native.darwin-universal.node')
|
|
115
|
+
} else {
|
|
116
|
+
nativeBinding = require('@oxide-js/spiking-darwin-universal')
|
|
117
|
+
}
|
|
118
|
+
break
|
|
119
|
+
} catch {}
|
|
120
|
+
switch (arch) {
|
|
121
|
+
case 'x64':
|
|
122
|
+
localFileExisted = existsSync(join(__dirname, 'spiking-native.darwin-x64.node'))
|
|
123
|
+
try {
|
|
124
|
+
if (localFileExisted) {
|
|
125
|
+
nativeBinding = require('./spiking-native.darwin-x64.node')
|
|
126
|
+
} else {
|
|
127
|
+
nativeBinding = require('@oxide-js/spiking-darwin-x64')
|
|
128
|
+
}
|
|
129
|
+
} catch (e) {
|
|
130
|
+
loadError = e
|
|
131
|
+
}
|
|
132
|
+
break
|
|
133
|
+
case 'arm64':
|
|
134
|
+
localFileExisted = existsSync(
|
|
135
|
+
join(__dirname, 'spiking-native.darwin-arm64.node')
|
|
136
|
+
)
|
|
137
|
+
try {
|
|
138
|
+
if (localFileExisted) {
|
|
139
|
+
nativeBinding = require('./spiking-native.darwin-arm64.node')
|
|
140
|
+
} else {
|
|
141
|
+
nativeBinding = require('@oxide-js/spiking-darwin-arm64')
|
|
142
|
+
}
|
|
143
|
+
} catch (e) {
|
|
144
|
+
loadError = e
|
|
145
|
+
}
|
|
146
|
+
break
|
|
147
|
+
default:
|
|
148
|
+
throw new Error(`Unsupported architecture on macOS: ${arch}`)
|
|
149
|
+
}
|
|
150
|
+
break
|
|
151
|
+
case 'freebsd':
|
|
152
|
+
if (arch !== 'x64') {
|
|
153
|
+
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
|
|
154
|
+
}
|
|
155
|
+
localFileExisted = existsSync(join(__dirname, 'spiking-native.freebsd-x64.node'))
|
|
156
|
+
try {
|
|
157
|
+
if (localFileExisted) {
|
|
158
|
+
nativeBinding = require('./spiking-native.freebsd-x64.node')
|
|
159
|
+
} else {
|
|
160
|
+
nativeBinding = require('@oxide-js/spiking-freebsd-x64')
|
|
161
|
+
}
|
|
162
|
+
} catch (e) {
|
|
163
|
+
loadError = e
|
|
164
|
+
}
|
|
165
|
+
break
|
|
166
|
+
case 'linux':
|
|
167
|
+
switch (arch) {
|
|
168
|
+
case 'x64':
|
|
169
|
+
if (isMusl()) {
|
|
170
|
+
localFileExisted = existsSync(
|
|
171
|
+
join(__dirname, 'spiking-native.linux-x64-musl.node')
|
|
172
|
+
)
|
|
173
|
+
try {
|
|
174
|
+
if (localFileExisted) {
|
|
175
|
+
nativeBinding = require('./spiking-native.linux-x64-musl.node')
|
|
176
|
+
} else {
|
|
177
|
+
nativeBinding = require('@oxide-js/spiking-linux-x64-musl')
|
|
178
|
+
}
|
|
179
|
+
} catch (e) {
|
|
180
|
+
loadError = e
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
localFileExisted = existsSync(
|
|
184
|
+
join(__dirname, 'spiking-native.linux-x64-gnu.node')
|
|
185
|
+
)
|
|
186
|
+
try {
|
|
187
|
+
if (localFileExisted) {
|
|
188
|
+
nativeBinding = require('./spiking-native.linux-x64-gnu.node')
|
|
189
|
+
} else {
|
|
190
|
+
nativeBinding = require('@oxide-js/spiking-linux-x64-gnu')
|
|
191
|
+
}
|
|
192
|
+
} catch (e) {
|
|
193
|
+
loadError = e
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
break
|
|
197
|
+
case 'arm64':
|
|
198
|
+
if (isMusl()) {
|
|
199
|
+
localFileExisted = existsSync(
|
|
200
|
+
join(__dirname, 'spiking-native.linux-arm64-musl.node')
|
|
201
|
+
)
|
|
202
|
+
try {
|
|
203
|
+
if (localFileExisted) {
|
|
204
|
+
nativeBinding = require('./spiking-native.linux-arm64-musl.node')
|
|
205
|
+
} else {
|
|
206
|
+
nativeBinding = require('@oxide-js/spiking-linux-arm64-musl')
|
|
207
|
+
}
|
|
208
|
+
} catch (e) {
|
|
209
|
+
loadError = e
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
localFileExisted = existsSync(
|
|
213
|
+
join(__dirname, 'spiking-native.linux-arm64-gnu.node')
|
|
214
|
+
)
|
|
215
|
+
try {
|
|
216
|
+
if (localFileExisted) {
|
|
217
|
+
nativeBinding = require('./spiking-native.linux-arm64-gnu.node')
|
|
218
|
+
} else {
|
|
219
|
+
nativeBinding = require('@oxide-js/spiking-linux-arm64-gnu')
|
|
220
|
+
}
|
|
221
|
+
} catch (e) {
|
|
222
|
+
loadError = e
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
break
|
|
226
|
+
case 'arm':
|
|
227
|
+
if (isMusl()) {
|
|
228
|
+
localFileExisted = existsSync(
|
|
229
|
+
join(__dirname, 'spiking-native.linux-arm-musleabihf.node')
|
|
230
|
+
)
|
|
231
|
+
try {
|
|
232
|
+
if (localFileExisted) {
|
|
233
|
+
nativeBinding = require('./spiking-native.linux-arm-musleabihf.node')
|
|
234
|
+
} else {
|
|
235
|
+
nativeBinding = require('@oxide-js/spiking-linux-arm-musleabihf')
|
|
236
|
+
}
|
|
237
|
+
} catch (e) {
|
|
238
|
+
loadError = e
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
localFileExisted = existsSync(
|
|
242
|
+
join(__dirname, 'spiking-native.linux-arm-gnueabihf.node')
|
|
243
|
+
)
|
|
244
|
+
try {
|
|
245
|
+
if (localFileExisted) {
|
|
246
|
+
nativeBinding = require('./spiking-native.linux-arm-gnueabihf.node')
|
|
247
|
+
} else {
|
|
248
|
+
nativeBinding = require('@oxide-js/spiking-linux-arm-gnueabihf')
|
|
249
|
+
}
|
|
250
|
+
} catch (e) {
|
|
251
|
+
loadError = e
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
break
|
|
255
|
+
case 'riscv64':
|
|
256
|
+
if (isMusl()) {
|
|
257
|
+
localFileExisted = existsSync(
|
|
258
|
+
join(__dirname, 'spiking-native.linux-riscv64-musl.node')
|
|
259
|
+
)
|
|
260
|
+
try {
|
|
261
|
+
if (localFileExisted) {
|
|
262
|
+
nativeBinding = require('./spiking-native.linux-riscv64-musl.node')
|
|
263
|
+
} else {
|
|
264
|
+
nativeBinding = require('@oxide-js/spiking-linux-riscv64-musl')
|
|
265
|
+
}
|
|
266
|
+
} catch (e) {
|
|
267
|
+
loadError = e
|
|
268
|
+
}
|
|
269
|
+
} else {
|
|
270
|
+
localFileExisted = existsSync(
|
|
271
|
+
join(__dirname, 'spiking-native.linux-riscv64-gnu.node')
|
|
272
|
+
)
|
|
273
|
+
try {
|
|
274
|
+
if (localFileExisted) {
|
|
275
|
+
nativeBinding = require('./spiking-native.linux-riscv64-gnu.node')
|
|
276
|
+
} else {
|
|
277
|
+
nativeBinding = require('@oxide-js/spiking-linux-riscv64-gnu')
|
|
278
|
+
}
|
|
279
|
+
} catch (e) {
|
|
280
|
+
loadError = e
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
break
|
|
284
|
+
case 's390x':
|
|
285
|
+
localFileExisted = existsSync(
|
|
286
|
+
join(__dirname, 'spiking-native.linux-s390x-gnu.node')
|
|
287
|
+
)
|
|
288
|
+
try {
|
|
289
|
+
if (localFileExisted) {
|
|
290
|
+
nativeBinding = require('./spiking-native.linux-s390x-gnu.node')
|
|
291
|
+
} else {
|
|
292
|
+
nativeBinding = require('@oxide-js/spiking-linux-s390x-gnu')
|
|
293
|
+
}
|
|
294
|
+
} catch (e) {
|
|
295
|
+
loadError = e
|
|
296
|
+
}
|
|
297
|
+
break
|
|
298
|
+
default:
|
|
299
|
+
throw new Error(`Unsupported architecture on Linux: ${arch}`)
|
|
300
|
+
}
|
|
301
|
+
break
|
|
302
|
+
default:
|
|
303
|
+
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (!nativeBinding) {
|
|
307
|
+
if (loadError) {
|
|
308
|
+
throw loadError
|
|
309
|
+
}
|
|
310
|
+
throw new Error(`Failed to load native binding`)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const { NativeSpikingNetwork, dotProductAddOnlyNative } = nativeBinding
|
|
314
|
+
|
|
315
|
+
module.exports.NativeSpikingNetwork = NativeSpikingNetwork
|
|
316
|
+
module.exports.dotProductAddOnlyNative = dotProductAddOnlyNative
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oxide-js/spiking",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Oxide-JS Spiking: Add-Only Event-Driven Spiking Neural Network implementation.",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/Akhyar11/Oxide-JS.git",
|
|
9
|
+
"directory": "packages/spiking"
|
|
10
|
+
},
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"types": "dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"napi": {
|
|
21
|
+
"name": "spiking-native"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"build:rust": "napi build --platform --release --cargo-cwd src-rust",
|
|
26
|
+
"postinstall": "node -e \"try{require('child_process').execSync('npm run build:rust',{stdio:'inherit'})}catch(e){console.warn('[oxide-js/spiking] Rust native build skipped')}\""
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"snn",
|
|
30
|
+
"spiking",
|
|
31
|
+
"neuromorphic",
|
|
32
|
+
"add-only",
|
|
33
|
+
"oxide-js"
|
|
34
|
+
],
|
|
35
|
+
"author": "Akhyar",
|
|
36
|
+
"license": "ISC",
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"@napi-rs/cli": "^2.18.0",
|
|
42
|
+
"@napi-rs/wasm-runtime": "^0.2.4"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"typescript": "^6.0.3"
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
|
|
2
|
+
export { default as dotProductAddOnly } from "./math/dotProductAddOnly.js";
|
|
3
|
+
export { SpikingDense, type SpikingDenseConfig } from "./layers/SpikingDense.js";
|
|
4
|
+
export { SpikingEmbedding, type SpikingEmbeddingConfig } from "./layers/SpikingEmbedding.js";
|
|
5
|
+
export { SpikingSentenceEmbedder, type SpikingSentenceConfig } from "./models/SpikingSentenceEmbedder.js";
|