Supernova11c commited on
Commit
77784b9
·
verified ·
1 Parent(s): 477f1ec

Publish Supernova Mathos V6.1

Browse files
Files changed (6) hide show
  1. LICENSE +202 -0
  2. NOTICE +5 -0
  3. README.md +37 -0
  4. __init__.py +4 -0
  5. mathos.py +357 -0
  6. weights/supernova_mathos_v6_1.npz +3 -0
LICENSE ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
NOTICE ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Supernova Mathos V6.1
2
+ Copyright 2026 Supernova
3
+
4
+ This product is licensed under the Apache License, Version 2.0.
5
+ The license text is provided in the LICENSE file.
README.md ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - arithmetic
5
+ - mathematics
6
+ - numpy
7
+ - supernova
8
+ ---
9
+
10
+ # Supernova Mathos V6.1
11
+
12
+ A custom NumPy-based learned arithmetic model with a BODMAS expression evaluator.
13
+
14
+ ## Installation
15
+
16
+ pip install supernova-mathos==6.1.0
17
+
18
+ ## Example
19
+
20
+ from supernova_mathos import mathos
21
+
22
+ model = mathos()
23
+ print(model.add(27, 15))
24
+ print(model.multiply(6, 7))
25
+ print(model.calculate("2 + 3 * 4"))
26
+
27
+ ## Files
28
+
29
+ - weights/supernova_mathos_v6_1.npz: trained weights
30
+ - mathos.py: model implementation
31
+ - LICENSE: Apache License 2.0
32
+
33
+ Test results apply to the tested inputs and do not guarantee correctness for every possible input.
34
+
35
+ ## License
36
+
37
+ Apache-2.0.
__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ """Supernova Mathos V6.1."""
2
+ from .mathos import mathos
3
+
4
+ __all__ = ["mathos"]
mathos.py ADDED
@@ -0,0 +1,357 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ import numpy as np
3
+ from fractions import Fraction
4
+
5
+
6
+ HIDDEN = 128
7
+
8
+ BATCH_SIZE = 128
9
+
10
+ LEARNING_RATE = 0.003
11
+
12
+ OP_NAMES = ['+', '-', '*', '/']
13
+
14
+ INPUT_SIZE = 34
15
+
16
+ def encode(a, b, state, op):
17
+ x = np.zeros(INPUT_SIZE, dtype=np.float64)
18
+ x[a] = 1.0
19
+ x[10 + b] = 1.0
20
+ x[20 + state] = 1.0
21
+ x[30 + op] = 1.0
22
+ return x
23
+
24
+ def build_data():
25
+ datasets = {op: [] for op in range(4)}
26
+ for a in range(10):
27
+ for b in range(10):
28
+ for carry in range(2):
29
+ total = a + b + carry
30
+ datasets[0].append((encode(a, b, carry, 0), total % 10, total // 10))
31
+ for a in range(10):
32
+ for b in range(10):
33
+ for borrow in range(2):
34
+ total = a - b - borrow
35
+ digit = total % 10
36
+ next_borrow = int(total < 0)
37
+ datasets[1].append((encode(a, b, borrow, 1), digit, next_borrow))
38
+ for a in range(10):
39
+ for b in range(10):
40
+ for carry in range(9):
41
+ total = a * b + carry
42
+ datasets[2].append((encode(a, b, carry, 2), total % 10, total // 10))
43
+ for divisor in range(1, 10):
44
+ for remainder in range(divisor):
45
+ for next_digit in range(10):
46
+ current = remainder * 10 + next_digit
47
+ quotient_digit = current // divisor
48
+ next_remainder = current % divisor
49
+ datasets[3].append((encode(next_digit, divisor, remainder, 3), quotient_digit, next_remainder))
50
+ result = {}
51
+ for op, rows in datasets.items():
52
+ result[op] = (np.stack([r[0] for r in rows]), np.array([r[1] for r in rows], dtype=np.int64), np.array([r[2] for r in rows], dtype=np.int64))
53
+ return result
54
+
55
+ DATA = build_data()
56
+
57
+ def softmax(z):
58
+ z = z - np.max(z, axis=1, keepdims=True)
59
+ e = np.exp(z)
60
+ return e / np.sum(e, axis=1, keepdims=True)
61
+
62
+ class MathosV6:
63
+
64
+ def __init__(self, seed=77):
65
+ r = np.random.default_rng(seed)
66
+
67
+ def init(nin, nout):
68
+ limit = np.sqrt(6.0 / (nin + nout))
69
+ return r.uniform(-limit, limit, (nin, nout))
70
+ self.p = {'W1': init(INPUT_SIZE, HIDDEN), 'b1': np.zeros((1, HIDDEN)), 'Wd': init(HIDDEN, 10), 'bd': np.zeros((1, 10)), 'Ws': init(HIDDEN, 10), 'bs': np.zeros((1, 10))}
71
+ self.m = {k: np.zeros_like(v) for k, v in self.p.items()}
72
+ self.v = {k: np.zeros_like(v) for k, v in self.p.items()}
73
+ self.step = 0
74
+ self.experiences_seen = 0
75
+
76
+ def forward(self, X):
77
+ h = np.tanh(X @ self.p['W1'] + self.p['b1'])
78
+ return (h, h @ self.p['Wd'] + self.p['bd'], h @ self.p['Ws'] + self.p['bs'])
79
+
80
+ def train_batch(self, X, yd, ys):
81
+ n = len(X)
82
+ h, dl, sl = self.forward(X)
83
+ pd, ps = (softmax(dl), softmax(sl))
84
+ rows = np.arange(n)
85
+ gd, gs = (pd.copy(), ps.copy())
86
+ gd[rows, yd] -= 1.0
87
+ gs[rows, ys] -= 1.0
88
+ gd /= n
89
+ gs /= n
90
+ grads = {'Wd': h.T @ gd, 'bd': gd.sum(axis=0, keepdims=True), 'Ws': h.T @ gs, 'bs': gs.sum(axis=0, keepdims=True)}
91
+ dh = gd @ self.p['Wd'].T + gs @ self.p['Ws'].T
92
+ dz = dh * (1.0 - h * h)
93
+ grads['W1'] = X.T @ dz
94
+ grads['b1'] = dz.sum(axis=0, keepdims=True)
95
+ self.step += 1
96
+ for k in self.p:
97
+ g = grads[k]
98
+ self.m[k] = 0.9 * self.m[k] + 0.1 * g
99
+ self.v[k] = 0.999 * self.v[k] + 0.001 * g * g
100
+ mhat = self.m[k] / (1.0 - 0.9 ** self.step)
101
+ vhat = self.v[k] / (1.0 - 0.999 ** self.step)
102
+ self.p[k] -= LEARNING_RATE * mhat / (np.sqrt(vhat) + 1e-08)
103
+ self.experiences_seen += n
104
+ loss_d = -np.log(pd[rows, yd] + 1e-12).mean()
105
+ loss_s = -np.log(ps[rows, ys] + 1e-12).mean()
106
+ return float(loss_d + loss_s)
107
+
108
+ def transition(self, a, b, state, op):
109
+ x = encode(a, b, state, op).reshape(1, -1)
110
+ _, dl, sl = self.forward(x)
111
+ return (int(dl[0].argmax()), int(sl[0].argmax()))
112
+
113
+ def transition_accuracy(self, op=None):
114
+ selected = range(4) if op is None else [op]
115
+ correct, total = (0, 0)
116
+ for operation in selected:
117
+ X, yd, ys = DATA[operation]
118
+ _, dl, sl = self.forward(X)
119
+ pd, ps = (dl.argmax(axis=1), sl.argmax(axis=1))
120
+ correct += int(np.sum((pd == yd) & (ps == ys)))
121
+ total += len(X)
122
+ return correct / total
123
+
124
+ def train_operation(self, op, epochs, seed):
125
+ X, yd, ys = DATA[op]
126
+ r = np.random.default_rng(seed)
127
+ name = OP_NAMES[op]
128
+ for ep in range(1, epochs + 1):
129
+ order = r.permutation(len(X))
130
+ total_loss = 0.0
131
+ for start in range(0, len(X), BATCH_SIZE):
132
+ ids = order[start:start + BATCH_SIZE]
133
+ loss = self.train_batch(X[ids], yd[ids], ys[ids])
134
+ total_loss += loss * len(ids)
135
+ total_loss /= len(X)
136
+ if ep == 1 or ep % 50 == 0 or ep == epochs:
137
+ acc = self.transition_accuracy(op)
138
+ print(f'Learn {name} | Epoch {ep:03d}/{epochs} | loss={total_loss:.5f} | transition accuracy={100 * acc:.2f}%')
139
+
140
+ def add(self, a, b):
141
+ if a < 0 or b < 0:
142
+ raise ValueError('Addition accepts nonnegative integers.')
143
+ result, carry, pos = (0, 0, 0)
144
+ while pos < max(len(str(a)), len(str(b))) or carry:
145
+ da = a // 10 ** pos % 10
146
+ db = b // 10 ** pos % 10
147
+ digit, carry = self.transition(da, db, carry, 0)
148
+ result += digit * 10 ** pos
149
+ pos += 1
150
+ return result
151
+
152
+ def subtract(self, a, b):
153
+ if a < b or b < 0:
154
+ raise ValueError('Subtraction requires a >= b >= 0.')
155
+ result, borrow = (0, 0)
156
+ for pos in range(len(str(a))):
157
+ da = a // 10 ** pos % 10
158
+ db = b // 10 ** pos % 10
159
+ digit, borrow = self.transition(da, db, borrow, 1)
160
+ result += digit * 10 ** pos
161
+ if borrow != 0:
162
+ raise ArithmeticError('Learned subtraction ended with a borrow.')
163
+ return result
164
+
165
+ def multiply_digit(self, n, digit):
166
+ if not 0 <= digit <= 9:
167
+ raise ValueError('Single-digit multiplier must be 0..9.')
168
+ result, carry, pos = (0, 0, 0)
169
+ while pos < len(str(n)) or carry:
170
+ da = n // 10 ** pos % 10
171
+ out_digit, carry = self.transition(da, digit, carry, 2)
172
+ result += out_digit * 10 ** pos
173
+ pos += 1
174
+ return result
175
+
176
+ def multiply(self, a, b):
177
+ if a < 0 or b < 0:
178
+ raise ValueError('Multiplication accepts nonnegative integers.')
179
+ result = 0
180
+ for pos, ch in enumerate(str(b)[::-1]):
181
+ partial = self.multiply_digit(a, int(ch))
182
+ for _ in range(pos):
183
+ partial *= 10
184
+ result = self.add(result, partial)
185
+ return result
186
+
187
+ def divide(self, dividend, divisor):
188
+ if dividend < 0 or divisor <= 0:
189
+ raise ValueError('Division requires dividend >= 0, divisor > 0.')
190
+ quotient, remainder = (0, 0)
191
+ for ch in str(dividend):
192
+ digit = int(ch)
193
+ if divisor <= 9:
194
+ qdigit, new_remainder = self.transition(digit, divisor, remainder, 3)
195
+ else:
196
+ current = int(str(remainder) + ch)
197
+ qdigit = 0
198
+ for trial in range(9, -1, -1):
199
+ product = self.multiply(divisor, trial)
200
+ if product <= current:
201
+ qdigit = trial
202
+ break
203
+ product = self.multiply(divisor, qdigit)
204
+ new_remainder = self.subtract(current, product)
205
+ quotient = quotient * 10 + qdigit
206
+ remainder = new_remainder
207
+ return (quotient, remainder)
208
+
209
+ def save(self, path):
210
+ np.savez(path, **self.p, experiences_seen=np.array(self.experiences_seen))
211
+
212
+ def signed_add(model, x, y, subtract=False):
213
+ if subtract:
214
+ y = -y
215
+ sx = -1 if x < 0 else 1
216
+ sy = -1 if y < 0 else 1
217
+ ax, ay = (abs(x), abs(y))
218
+ if sx == sy:
219
+ return sx * model.add(ax, ay)
220
+ if ax >= ay:
221
+ return sx * model.subtract(ax, ay)
222
+ return sy * model.subtract(ay, ax)
223
+
224
+ def signed_multiply(model, x, y):
225
+ sign = -1 if (x < 0) != (y < 0) else 1
226
+ return sign * model.multiply(abs(x), abs(y))
227
+
228
+ def fraction_operation(model, left, right, op):
229
+ left, right = (Fraction(left), Fraction(right))
230
+ if op == '+' or op == '-':
231
+ n1 = signed_multiply(model, left.numerator, right.denominator)
232
+ n2 = signed_multiply(model, right.numerator, left.denominator)
233
+ numerator = signed_add(model, n1, n2, subtract=op == '-')
234
+ denominator = model.multiply(left.denominator, right.denominator)
235
+ return Fraction(numerator, denominator)
236
+ if op == '*':
237
+ numerator = signed_multiply(model, left.numerator, right.numerator)
238
+ denominator = model.multiply(left.denominator, right.denominator)
239
+ return Fraction(numerator, denominator)
240
+ if op == '/':
241
+ if right == 0:
242
+ raise ZeroDivisionError('Division by zero.')
243
+ numerator = signed_multiply(model, left.numerator, right.denominator)
244
+ denominator = signed_multiply(model, left.denominator, right.numerator)
245
+ return Fraction(numerator, denominator)
246
+ raise ValueError('Unsupported operation.')
247
+
248
+ def fraction_power(model, base, exponent):
249
+ base = Fraction(base)
250
+ exponent = Fraction(exponent)
251
+ if exponent.denominator != 1:
252
+ raise ValueError('Only integer powers are supported.')
253
+ power = exponent.numerator
254
+ if abs(power) > 20:
255
+ raise ValueError('Power magnitude is limited to 20.')
256
+ if power < 0:
257
+ if base == 0:
258
+ raise ZeroDivisionError('Zero cannot have a negative power.')
259
+ base = Fraction(base.denominator, base.numerator)
260
+ power = -power
261
+ result = Fraction(1, 1)
262
+ for _ in range(power):
263
+ result = fraction_operation(model, result, base, '*')
264
+ return result
265
+
266
+ def tokenize(expression):
267
+ cleaned = re.sub('\\s+', '', expression)
268
+ tokens = re.findall('\\d+|[()+*/^%-]', cleaned)
269
+ if ''.join(tokens) != cleaned:
270
+ raise ValueError('Invalid character in expression.')
271
+ return tokens
272
+
273
+ def bodmas(model, expression):
274
+ tokens = tokenize(expression)
275
+ index = 0
276
+
277
+ def parse_expression():
278
+ nonlocal index
279
+ value = parse_term()
280
+ while index < len(tokens) and tokens[index] in ('+', '-'):
281
+ op = tokens[index]
282
+ index += 1
283
+ rhs = parse_term()
284
+ value = fraction_operation(model, value, rhs, op)
285
+ return value
286
+
287
+ def parse_term():
288
+ nonlocal index
289
+ value = parse_power()
290
+ while index < len(tokens) and tokens[index] in ('*', '/'):
291
+ op = tokens[index]
292
+ index += 1
293
+ rhs = parse_power()
294
+ value = fraction_operation(model, value, rhs, op)
295
+ return value
296
+
297
+ def parse_power():
298
+ nonlocal index
299
+ value = parse_factor()
300
+ if index < len(tokens) and tokens[index] == '^':
301
+ index += 1
302
+ exponent = parse_power()
303
+ value = fraction_power(model, value, exponent)
304
+ return value
305
+
306
+ def parse_factor():
307
+ nonlocal index
308
+ if index >= len(tokens):
309
+ raise ValueError('Incomplete expression.')
310
+ if tokens[index] == '+':
311
+ index += 1
312
+ return parse_factor()
313
+ if tokens[index] == '-':
314
+ index += 1
315
+ return -parse_factor()
316
+ if tokens[index] == '(':
317
+ index += 1
318
+ value = parse_expression()
319
+ if index >= len(tokens) or tokens[index] != ')':
320
+ raise ValueError('Missing closing parenthesis.')
321
+ index += 1
322
+ return value
323
+ token = tokens[index]
324
+ if not token.isdigit():
325
+ raise ValueError(f'Unexpected token: {token}')
326
+ index += 1
327
+ return Fraction(int(token), 1)
328
+ result = parse_expression()
329
+ if index != len(tokens):
330
+ raise ValueError('Unexpected trailing tokens.')
331
+ return result
332
+
333
+
334
+ from importlib.resources import files
335
+
336
+ class mathos:
337
+ """Supernova Mathos V6.1 with bundled trained NumPy weights."""
338
+
339
+ def __init__(self):
340
+ self.model = MathosV6(seed=77)
341
+ weight_path = files("supernova_mathos").joinpath(
342
+ "weights/supernova_mathos_v6_1.npz"
343
+ )
344
+ with np.load(weight_path) as saved:
345
+ self.model.p = {
346
+ key: saved[key].copy()
347
+ for key in ("W1", "b1", "Wd", "bd", "Ws", "bs")
348
+ }
349
+ if "experiences_seen" in saved:
350
+ self.model.experiences_seen = int(saved["experiences_seen"])
351
+
352
+ def __getattr__(self, name):
353
+ return getattr(self.model, name)
354
+
355
+ def calculate(self, expression):
356
+ return bodmas(self.model, expression)
357
+
weights/supernova_mathos_v6_1.npz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d0dc8a525b6c81b9acf7a14f0b5797a3154118b7a6c9fa074c6e224a8912bc73
3
+ size 58190