maten 0.1.0__py3-none-any.whl

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.
maten/__init__.py ADDED
@@ -0,0 +1,57 @@
1
+ """
2
+ maten — Pure Python scientific computing library
3
+ =================================================
4
+ Single import replaces NumPy + Pandas + Matplotlib + TensorFlow.
5
+
6
+ import maten as mt
7
+
8
+ mt.array(...) # arrays
9
+ mt.DataFrame(...) # dataframes
10
+ mt.subplots() # plots
11
+ mt.Sequential(...) # neural networks
12
+ """
13
+
14
+ __version__ = "0.1.0"
15
+ __author__ = "maten contributors"
16
+
17
+ # ── core (NumPy replacement) ──────────────────────────────────
18
+ from maten.core.tensor import Tensor, array, matmul
19
+ from maten.core.creation import (zeros, ones, full, eye, arange, linspace,
20
+ rand, randn, randint, concatenate, stack)
21
+ from maten.core.math_ops import (sqrt, exp, log, log2, log10,
22
+ sin, cos, tan, tanh,
23
+ abs_, ceil, floor,
24
+ sigmoid, relu, leaky_relu,
25
+ clip, softmax, where, unique, sort)
26
+ from maten.core.linalg import linalg
27
+
28
+ # ── frame (Pandas replacement) ────────────────────────────────
29
+ from maten.frame.series import Series
30
+ from maten.frame.dataframe import DataFrame
31
+ from maten.frame.groupby import GroupBy
32
+ from maten.frame.io import read_csv, read_json, concat as concat_frames
33
+
34
+ # ── plot (Matplotlib replacement) ─────────────────────────────
35
+ from maten.plot.figure import (Figure, Axes,
36
+ figure, subplots, show, savefig,
37
+ plot, scatter, bar, barh, hist,
38
+ fill_between, axhline, axvline,
39
+ xlabel, ylabel, title, legend, xlim, ylim)
40
+ from maten.plot.charts import pie, heatmap
41
+
42
+ # ── neural (TensorFlow replacement) ───────────────────────────
43
+ from maten.neural.autograd import Value
44
+ from maten.neural.sequential import Module, Sequential
45
+ from maten.neural.layers import (Parameter, Linear,
46
+ ReLU, Sigmoid, Tanh, Softmax,
47
+ LeakyReLU, Dropout, BatchNorm1d, Flatten)
48
+ from maten.neural.losses import (MSELoss, MAELoss, BCELoss,
49
+ CrossEntropyLoss, HuberLoss)
50
+ from maten.neural.optimizers import SGD, Adam, AdamW, RMSProp, Adagrad
51
+ from maten.neural.metrics import (accuracy, mean_squared_error,
52
+ mean_absolute_error, r2_score, rmse,
53
+ precision, recall, f1_score, confusion_matrix)
54
+ from maten.neural.dataloader import DataLoader, Trainer
55
+
56
+ # ── neural tensor (separate namespace to avoid clash with core)
57
+ from maten.neural import tensor as nn_tensor
maten/core/creation.py ADDED
@@ -0,0 +1,68 @@
1
+ """
2
+ maten.core.creation — array creation functions
3
+ """
4
+
5
+ import random
6
+ from functools import reduce
7
+ import operator
8
+ from maten.core.tensor import Tensor
9
+
10
+
11
+ def zeros(shape, dtype=float):
12
+ if isinstance(shape, int): shape = (shape,)
13
+ size = reduce(operator.mul, shape, 1)
14
+ return Tensor._make([dtype(0)] * size, shape, dtype)
15
+
16
+ def ones(shape, dtype=float):
17
+ if isinstance(shape, int): shape = (shape,)
18
+ size = reduce(operator.mul, shape, 1)
19
+ return Tensor._make([dtype(1)] * size, shape, dtype)
20
+
21
+ def full(shape, fill_value, dtype=float):
22
+ if isinstance(shape, int): shape = (shape,)
23
+ size = reduce(operator.mul, shape, 1)
24
+ return Tensor._make([dtype(fill_value)] * size, shape, dtype)
25
+
26
+ def eye(n, dtype=float):
27
+ t = zeros((n, n), dtype=dtype)
28
+ for i in range(n):
29
+ t._data[i * n + i] = dtype(1)
30
+ return t
31
+
32
+ def arange(start, stop=None, step=1, dtype=float):
33
+ if stop is None: start, stop = 0, start
34
+ data, v = [], start
35
+ while (step > 0 and v < stop) or (step < 0 and v > stop):
36
+ data.append(dtype(v)); v += step
37
+ return Tensor._make(data, (len(data),), dtype)
38
+
39
+ def linspace(start, stop, num=50, dtype=float):
40
+ if num == 1:
41
+ return Tensor._make([dtype(start)], (1,), dtype)
42
+ step = (stop - start) / (num - 1)
43
+ data = [dtype(start + i * step) for i in range(num)]
44
+ return Tensor._make(data, (num,), dtype)
45
+
46
+ def rand(*shape):
47
+ size = reduce(operator.mul, shape, 1)
48
+ return Tensor._make([random.random() for _ in range(size)], shape, float)
49
+
50
+ def randn(*shape):
51
+ size = reduce(operator.mul, shape, 1)
52
+ return Tensor._make([random.gauss(0, 1) for _ in range(size)], shape, float)
53
+
54
+ def randint(low, high, shape):
55
+ if isinstance(shape, int): shape = (shape,)
56
+ size = reduce(operator.mul, shape, 1)
57
+ return Tensor._make([float(random.randint(low, high - 1)) for _ in range(size)], shape, float)
58
+
59
+ def concatenate(tensors, axis=0):
60
+ if axis == 0:
61
+ data = []
62
+ for t in tensors: data.extend(t._data)
63
+ new_shape = (sum(t._shape[0] for t in tensors),) + tensors[0]._shape[1:]
64
+ return Tensor._make(data, new_shape, tensors[0].dtype)
65
+ raise NotImplementedError("concatenate on axis != 0 coming soon")
66
+
67
+ def stack(tensors, axis=0):
68
+ return concatenate([t.expand_dims(axis) for t in tensors], axis=axis)
maten/core/linalg.py ADDED
@@ -0,0 +1,78 @@
1
+ """
2
+ maten.core.linalg — linear algebra operations
3
+ """
4
+
5
+ import math
6
+ import operator
7
+ from functools import reduce
8
+ from maten.core.tensor import Tensor, matmul
9
+
10
+
11
+ class linalg:
12
+
13
+ @staticmethod
14
+ def norm(t, ord=2):
15
+ if ord == 2: return Tensor._make([math.sqrt(sum(x**2 for x in t._data))], (1,), float)
16
+ elif ord == 1: return Tensor._make([sum(abs(x) for x in t._data)], (1,), float)
17
+ elif ord == float('inf'): return Tensor._make([max(abs(x) for x in t._data)], (1,), float)
18
+ raise ValueError(f"Unsupported norm order: {ord}")
19
+
20
+ @staticmethod
21
+ def dot(a, b):
22
+ return a.dot(b)
23
+
24
+ @staticmethod
25
+ def matmul(a, b):
26
+ return matmul(a, b)
27
+
28
+ @staticmethod
29
+ def transpose(t):
30
+ return t.T
31
+
32
+ @staticmethod
33
+ def trace(t):
34
+ assert t.ndim == 2 and t._shape[0] == t._shape[1]
35
+ n = t._shape[0]
36
+ return Tensor._make([sum(t._data[i * n + i] for i in range(n))], (1,), float)
37
+
38
+ @staticmethod
39
+ def det(t):
40
+ assert t.ndim == 2 and t._shape[0] == t._shape[1]
41
+ n = t._shape[0]
42
+ from maten.core.tensor import _make_nested
43
+ mat = [row[:] for row in _make_nested(t._data, t._shape)]
44
+ det = 1.0
45
+ for col in range(n):
46
+ pivot = next((r for r in range(col, n) if abs(mat[r][col]) > 1e-12), None)
47
+ if pivot is None: return Tensor._make([0.0], (1,), float)
48
+ if pivot != col:
49
+ mat[col], mat[pivot] = mat[pivot], mat[col]; det *= -1
50
+ det *= mat[col][col]
51
+ for row in range(col + 1, n):
52
+ f = mat[row][col] / mat[col][col]
53
+ for k in range(col, n):
54
+ mat[row][k] -= f * mat[col][k]
55
+ return Tensor._make([det], (1,), float)
56
+
57
+ @staticmethod
58
+ def inv(t):
59
+ assert t.ndim == 2 and t._shape[0] == t._shape[1]
60
+ n = t._shape[0]
61
+ from maten.core.tensor import _make_nested
62
+ mat = [row[:] for row in _make_nested(t._data, t._shape)]
63
+ inv = [[float(i == j) for j in range(n)] for i in range(n)]
64
+ for col in range(n):
65
+ pivot = next((r for r in range(col, n) if abs(mat[r][col]) > 1e-12), None)
66
+ if pivot is None: raise ValueError("Matrix is singular")
67
+ mat[col], mat[pivot] = mat[pivot], mat[col]
68
+ inv[col], inv[pivot] = inv[pivot], inv[col]
69
+ scale = mat[col][col]
70
+ mat[col] = [v / scale for v in mat[col]]
71
+ inv[col] = [v / scale for v in inv[col]]
72
+ for row in range(n):
73
+ if row != col:
74
+ f = mat[row][col]
75
+ mat[row] = [mat[row][k] - f * mat[col][k] for k in range(n)]
76
+ inv[row] = [inv[row][k] - f * inv[col][k] for k in range(n)]
77
+ flat = [v for row in inv for v in row]
78
+ return Tensor._make(flat, (n, n), float)
maten/core/math_ops.py ADDED
@@ -0,0 +1,56 @@
1
+ """
2
+ maten.core.math_ops — mathematical functions
3
+ """
4
+
5
+ import math
6
+ from maten.core.tensor import Tensor
7
+
8
+
9
+ def _apply(t, func):
10
+ if isinstance(t, (int, float)): return func(t)
11
+ return t.apply(func)
12
+
13
+ def sqrt(t): return _apply(t, math.sqrt)
14
+ def exp(t): return _apply(t, math.exp)
15
+ def log(t): return _apply(t, math.log)
16
+ def log2(t): return _apply(t, math.log2)
17
+ def log10(t): return _apply(t, math.log10)
18
+ def sin(t): return _apply(t, math.sin)
19
+ def cos(t): return _apply(t, math.cos)
20
+ def tan(t): return _apply(t, math.tan)
21
+ def tanh(t): return _apply(t, math.tanh)
22
+ def abs_(t): return _apply(t, abs)
23
+ def ceil(t): return _apply(t, math.ceil)
24
+ def floor(t): return _apply(t, math.floor)
25
+
26
+ def sigmoid(t):
27
+ return _apply(t, lambda x: 1 / (1 + math.exp(-x)))
28
+
29
+ def relu(t):
30
+ return _apply(t, lambda x: max(0.0, x))
31
+
32
+ def leaky_relu(t, alpha=0.01):
33
+ return _apply(t, lambda x: x if x > 0 else alpha * x)
34
+
35
+ def clip(t, min_val, max_val):
36
+ return _apply(t, lambda x: max(min_val, min(max_val, x)))
37
+
38
+ def softmax(t):
39
+ m = max(t._data)
40
+ exps = [math.exp(x - m) for x in t._data]
41
+ total = sum(exps)
42
+ return Tensor._make([e / total for e in exps], t._shape, float)
43
+
44
+ def where(condition, x, y):
45
+ data = [a if c else b for c, a, b in zip(condition._data, x._data, y._data)]
46
+ return Tensor._make(data, condition._shape, x.dtype)
47
+
48
+ def unique(t):
49
+ return sorted(set(t._data))
50
+
51
+ def sort(t):
52
+ return Tensor._make(sorted(t._data), t._shape, t.dtype)
53
+
54
+ def matmul(a, b):
55
+ from maten.core.tensor import matmul as _matmul
56
+ return _matmul(a, b)
maten/core/tensor.py ADDED
@@ -0,0 +1,250 @@
1
+ """
2
+ maten.core.tensor — N-dimensional Tensor class
3
+ """
4
+
5
+ import math
6
+ import operator
7
+ from functools import reduce
8
+ from copy import deepcopy
9
+
10
+
11
+ def _flat(nested):
12
+ if isinstance(nested, (int, float, bool)):
13
+ return [float(nested)]
14
+ out = []
15
+ for item in nested:
16
+ out.extend(_flat(item))
17
+ return out
18
+
19
+ def _shape_of(nested):
20
+ if not isinstance(nested, list):
21
+ return ()
22
+ if not nested:
23
+ return (0,)
24
+ return (len(nested),) + _shape_of(nested[0])
25
+
26
+ def _make_nested(flat, shape):
27
+ if len(shape) == 1:
28
+ return list(flat[:shape[0]])
29
+ size = reduce(operator.mul, shape[1:], 1)
30
+ return [_make_nested(flat[i*size:(i+1)*size], shape[1:]) for i in range(shape[0])]
31
+
32
+ def _broadcast_shapes(a, b):
33
+ ra, rb = list(reversed(a)), list(reversed(b))
34
+ out = []
35
+ for i in range(max(len(ra), len(rb))):
36
+ da = ra[i] if i < len(ra) else 1
37
+ db = rb[i] if i < len(rb) else 1
38
+ if da == db: out.append(da)
39
+ elif da == 1: out.append(db)
40
+ elif db == 1: out.append(da)
41
+ else: raise ValueError(f"Cannot broadcast shapes {a} and {b}")
42
+ return tuple(reversed(out))
43
+
44
+
45
+ class Tensor:
46
+ """N-dimensional array — core data structure of maten."""
47
+
48
+ def __init__(self, data, dtype=float, shape=None):
49
+ if isinstance(data, Tensor):
50
+ self._data = data._data[:]
51
+ self._shape = data._shape
52
+ elif isinstance(data, list):
53
+ self._data = [dtype(x) for x in _flat(data)]
54
+ self._shape = shape if shape else _shape_of(data)
55
+ elif isinstance(data, (int, float)):
56
+ self._data = [dtype(data)]
57
+ self._shape = ()
58
+ else:
59
+ raise TypeError(f"Unsupported type: {type(data)}")
60
+ self.dtype = dtype
61
+
62
+ # ── internal factory ──────────────────────────────────────
63
+ @classmethod
64
+ def _make(cls, data, shape, dtype=float):
65
+ t = cls.__new__(cls)
66
+ t._data = data
67
+ t._shape = shape
68
+ t.dtype = dtype
69
+ return t
70
+
71
+ # ── properties ────────────────────────────────────────────
72
+ @property
73
+ def shape(self): return self._shape
74
+
75
+ @property
76
+ def ndim(self): return len(self._shape)
77
+
78
+ @property
79
+ def size(self): return len(self._data)
80
+
81
+ @property
82
+ def T(self):
83
+ if self.ndim != 2:
84
+ raise ValueError("Transpose only supports 2D tensors.")
85
+ r, c = self._shape
86
+ data = [self._data[j * c + i] for i in range(c) for j in range(r)]
87
+ return Tensor._make(data, (c, r), self.dtype)
88
+
89
+ # ── indexing ──────────────────────────────────────────────
90
+ def _flat_index(self, idx):
91
+ strides, s = [], 1
92
+ for d in reversed(self._shape):
93
+ strides.insert(0, s); s *= d
94
+ return sum(i * st for i, st in zip(idx, strides))
95
+
96
+ def __getitem__(self, idx):
97
+ if isinstance(idx, tuple):
98
+ return self._data[self._flat_index(idx)]
99
+ if isinstance(idx, int):
100
+ if self.ndim == 1:
101
+ return self._data[idx]
102
+ size = self.size // self._shape[0]
103
+ sub = self._data[idx * size:(idx + 1) * size]
104
+ return Tensor._make(sub, self._shape[1:], self.dtype)
105
+ raise TypeError(f"Invalid index: {idx}")
106
+
107
+ def __setitem__(self, idx, value):
108
+ if isinstance(idx, int) and self.ndim == 1:
109
+ self._data[idx] = self.dtype(value)
110
+ elif isinstance(idx, tuple):
111
+ self._data[self._flat_index(idx)] = self.dtype(value)
112
+
113
+ # ── repr ──────────────────────────────────────────────────
114
+ def __repr__(self):
115
+ nested = _make_nested(self._data, self._shape) if self._shape else self._data[0]
116
+ return f"Tensor({nested}, shape={self._shape}, dtype={self.dtype.__name__})"
117
+
118
+ def tolist(self):
119
+ return _make_nested(self._data, self._shape) if self._shape else self._data[0]
120
+
121
+ # ── broadcast ─────────────────────────────────────────────
122
+ def broadcast_to(self, shape):
123
+ if self._shape == shape:
124
+ return self
125
+ padded = (1,) * (len(shape) - len(self._shape)) + self._shape
126
+ repeats = [s // p for s, p in zip(shape, padded)]
127
+ data = self._data[:]
128
+ cur = list(padded)
129
+ for axis, rep in enumerate(repeats):
130
+ if rep > 1:
131
+ sb = reduce(operator.mul, cur[:axis], 1)
132
+ sa = reduce(operator.mul, cur[axis:], 1) // cur[axis]
133
+ nd = []
134
+ for i in range(sb):
135
+ chunk = data[i * sa * cur[axis]:(i + 1) * sa * cur[axis]]
136
+ for _ in range(rep):
137
+ nd.extend(chunk[:sa])
138
+ data = nd
139
+ cur[axis] *= rep
140
+ return Tensor._make(data, shape, self.dtype)
141
+
142
+ # ── element-wise ops ──────────────────────────────────────
143
+ def _ew(self, other, op):
144
+ if isinstance(other, (int, float)):
145
+ return Tensor._make([op(x, other) for x in self._data], self._shape, self.dtype)
146
+ if isinstance(other, Tensor):
147
+ s = _broadcast_shapes(self._shape, other._shape)
148
+ a = self.broadcast_to(s); b = other.broadcast_to(s)
149
+ return Tensor._make([op(x, y) for x, y in zip(a._data, b._data)], s, self.dtype)
150
+ raise TypeError(f"Unsupported: {type(other)}")
151
+
152
+ def __add__(self, o): return self._ew(o, operator.add)
153
+ def __radd__(self, o): return self._ew(o, operator.add)
154
+ def __sub__(self, o): return self._ew(o, operator.sub)
155
+ def __rsub__(self, o): return self._ew(o, lambda a, b: b - a)
156
+ def __mul__(self, o): return self._ew(o, operator.mul)
157
+ def __rmul__(self, o): return self._ew(o, operator.mul)
158
+ def __truediv__(self, o): return self._ew(o, operator.truediv)
159
+ def __rtruediv__(self, o): return self._ew(o, lambda a, b: b / a)
160
+ def __pow__(self, e): return self._ew(e, operator.pow)
161
+ def __neg__(self): return Tensor._make([-x for x in self._data], self._shape, self.dtype)
162
+ def __abs__(self): return Tensor._make([abs(x) for x in self._data], self._shape, self.dtype)
163
+
164
+ def __eq__(self, o): return self._ew(o, lambda a, b: float(a == b))
165
+ def __lt__(self, o): return self._ew(o, lambda a, b: float(a < b))
166
+ def __le__(self, o): return self._ew(o, lambda a, b: float(a <= b))
167
+ def __gt__(self, o): return self._ew(o, lambda a, b: float(a > b))
168
+ def __ge__(self, o): return self._ew(o, lambda a, b: float(a >= b))
169
+
170
+ # ── reductions ────────────────────────────────────────────
171
+ def sum(self, axis=None):
172
+ if axis is None:
173
+ return Tensor._make([sum(self._data)], (1,), self.dtype)
174
+ os = self._shape[:axis] + self._shape[axis+1:]
175
+ osz = reduce(operator.mul, os, 1) if os else 1
176
+ res = [0.0] * osz
177
+ sa = reduce(operator.mul, self._shape[axis+1:], 1)
178
+ sb = reduce(operator.mul, self._shape[:axis], 1)
179
+ for i in range(sb):
180
+ for k in range(self._shape[axis]):
181
+ for j in range(sa):
182
+ res[i * sa + j] += self._data[i * self._shape[axis] * sa + k * sa + j]
183
+ return Tensor._make(res, os if os else (1,), self.dtype)
184
+
185
+ def mean(self, axis=None):
186
+ if axis is None:
187
+ return Tensor._make([sum(self._data) / len(self._data)], (1,), self.dtype)
188
+ return self.sum(axis=axis) / self._shape[axis]
189
+
190
+ def std(self, axis=None):
191
+ m = self.mean(axis=axis)
192
+ diff = self - m
193
+ return ((diff * diff).mean(axis=axis)) ** 0.5
194
+
195
+ def max(self, axis=None):
196
+ if axis is None:
197
+ return Tensor._make([max(self._data)], (1,), self.dtype)
198
+ raise NotImplementedError("axis max coming soon")
199
+
200
+ def min(self, axis=None):
201
+ if axis is None:
202
+ return Tensor._make([min(self._data)], (1,), self.dtype)
203
+ raise NotImplementedError("axis min coming soon")
204
+
205
+ def argmax(self): return self._data.index(max(self._data))
206
+ def argmin(self): return self._data.index(min(self._data))
207
+
208
+ # ── shape ops ─────────────────────────────────────────────
209
+ def reshape(self, *shape):
210
+ s = shape[0] if len(shape) == 1 and isinstance(shape[0], tuple) else shape
211
+ if -1 in s:
212
+ known = reduce(operator.mul, [x for x in s if x != -1], 1)
213
+ s = tuple(self.size // known if x == -1 else x for x in s)
214
+ assert reduce(operator.mul, s, 1) == self.size, "Shape mismatch"
215
+ return Tensor._make(self._data[:], s, self.dtype)
216
+
217
+ def flatten(self): return self.reshape(self.size)
218
+ def squeeze(self): return self.reshape(tuple(s for s in self._shape if s != 1) or (1,))
219
+ def expand_dims(self, axis):
220
+ s = list(self._shape); s.insert(axis, 1)
221
+ return self.reshape(tuple(s))
222
+
223
+ # ── matrix ops ────────────────────────────────────────────
224
+ def dot(self, other):
225
+ if self.ndim == 1 and other.ndim == 1:
226
+ return Tensor._make([sum(a * b for a, b in zip(self._data, other._data))], (1,), self.dtype)
227
+ return matmul(self, other)
228
+
229
+ def __matmul__(self, other): return matmul(self, other)
230
+
231
+ def apply(self, func):
232
+ return Tensor._make([func(x) for x in self._data], self._shape, self.dtype)
233
+
234
+
235
+ def matmul(a, b):
236
+ assert a.ndim == 2 and b.ndim == 2
237
+ m, k = a._shape; k2, n = b._shape
238
+ assert k == k2, f"Shape mismatch: {k} != {k2}"
239
+ res = [0.0] * (m * n)
240
+ for i in range(m):
241
+ for j in range(n):
242
+ s = 0.0
243
+ for p in range(k):
244
+ s += a._data[i * k + p] * b._data[p * n + j]
245
+ res[i * n + j] = s
246
+ return Tensor._make(res, (m, n), float)
247
+
248
+
249
+ def array(data, dtype=float):
250
+ return Tensor(data, dtype=dtype)
@@ -0,0 +1,15 @@
1
+ """Pandas-like Series and DataFrame utilities."""
2
+
3
+ from maten.frame.dataframe import DataFrame
4
+ from maten.frame.groupby import GroupBy
5
+ from maten.frame.io import concat, read_csv, read_json
6
+ from maten.frame.series import Series
7
+
8
+ __all__ = [
9
+ "Series",
10
+ "DataFrame",
11
+ "GroupBy",
12
+ "read_csv",
13
+ "read_json",
14
+ "concat",
15
+ ]