matlabpy 0.0.6__tar.gz → 0.0.8__tar.gz
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.
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: matlabpy
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.8
|
|
4
4
|
Summary: A Python library for MATLAB integration
|
|
5
5
|
Author: Daniel F. Hernández Gardiol
|
|
6
6
|
Author-email: dan.fhg@gmail.com
|
|
7
7
|
Requires-Python: >=3.14
|
|
8
8
|
Classifier: Programming Language :: Python :: 3
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.14
|
|
10
|
+
Requires-Dist: numpy (>=1.20.0)
|
|
10
11
|
Description-Content-Type: text/markdown
|
|
11
12
|
|
|
12
13
|
hopefully this will be version 6
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "matlabpy"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.8"
|
|
4
4
|
description = "A Python library for MATLAB integration"
|
|
5
5
|
repository = "https://github.com/wealing/matlabpy"
|
|
6
6
|
authors = [
|
|
@@ -9,6 +9,7 @@ authors = [
|
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.14"
|
|
11
11
|
dependencies = [
|
|
12
|
+
"numpy>=1.20.0"
|
|
12
13
|
]
|
|
13
14
|
|
|
14
15
|
[tool.poetry]
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""
|
|
2
|
+
matlabpy.py — A lightweight Python library that mimics core MATLAB matrix syntax & operators
|
|
3
|
+
|
|
4
|
+
Goals:
|
|
5
|
+
- MATLAB-like matrix construction: [1 2; 3 4]
|
|
6
|
+
- Elementwise vs matrix ops: + - * / ^ and .*, ./, .^
|
|
7
|
+
- Transpose: A.T and A' style via .T and .H
|
|
8
|
+
- Indexing: A(1,2) style via A(1,2) callable + Python slicing
|
|
9
|
+
- Concatenation: [A B; C D]
|
|
10
|
+
|
|
11
|
+
This is NOT a full MATLAB clone. It is a thin syntax layer over NumPy
|
|
12
|
+
intended for prototyping and familiarity, not performance-critical code.
|
|
13
|
+
|
|
14
|
+
Dependencies: numpy
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
import numpy as np
|
|
19
|
+
from typing import Iterable, Tuple, Union
|
|
20
|
+
|
|
21
|
+
Number = Union[int, float, complex]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class M:
|
|
25
|
+
"""MATLAB-like matrix wrapper around NumPy arrays."""
|
|
26
|
+
|
|
27
|
+
def __init__(self, data):
|
|
28
|
+
if isinstance(data, M):
|
|
29
|
+
self.A = data.A.copy()
|
|
30
|
+
else:
|
|
31
|
+
self.A = np.array(data, dtype=float)
|
|
32
|
+
|
|
33
|
+
# --------------------------
|
|
34
|
+
# Representation
|
|
35
|
+
# --------------------------
|
|
36
|
+
|
|
37
|
+
def __repr__(self):
|
|
38
|
+
return f"M({self.A})"
|
|
39
|
+
|
|
40
|
+
def __str__(self):
|
|
41
|
+
return str(self.A)
|
|
42
|
+
|
|
43
|
+
# --------------------------
|
|
44
|
+
# Indexing
|
|
45
|
+
# --------------------------
|
|
46
|
+
|
|
47
|
+
def __call__(self, *idx):
|
|
48
|
+
"""MATLAB-style indexing A(i,j). 1-based."""
|
|
49
|
+
idx = tuple(i - 1 if isinstance(i, int) else i for i in idx)
|
|
50
|
+
return self.A[idx]
|
|
51
|
+
|
|
52
|
+
def __getitem__(self, key):
|
|
53
|
+
return self.A[key]
|
|
54
|
+
|
|
55
|
+
def __setitem__(self, key, value):
|
|
56
|
+
self.A[key] = value
|
|
57
|
+
|
|
58
|
+
# --------------------------
|
|
59
|
+
# Shape helpers
|
|
60
|
+
# --------------------------
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def T(self):
|
|
64
|
+
return M(self.A.T)
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def H(self):
|
|
68
|
+
return M(self.A.conj().T)
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def shape(self):
|
|
72
|
+
return self.A.shape
|
|
73
|
+
|
|
74
|
+
# --------------------------
|
|
75
|
+
# Arithmetic Operators
|
|
76
|
+
# --------------------------
|
|
77
|
+
|
|
78
|
+
def __add__(self, other):
|
|
79
|
+
return M(self.A + _unwrap(other))
|
|
80
|
+
|
|
81
|
+
def __sub__(self, other):
|
|
82
|
+
return M(self.A - _unwrap(other))
|
|
83
|
+
|
|
84
|
+
def __mul__(self, other):
|
|
85
|
+
return M(self.A @ _unwrap(other)) # Matrix multiply
|
|
86
|
+
|
|
87
|
+
def __truediv__(self, other):
|
|
88
|
+
return M(self.A @ np.linalg.inv(_unwrap(other)))
|
|
89
|
+
|
|
90
|
+
def __pow__(self, p):
|
|
91
|
+
return M(np.linalg.matrix_power(self.A, p))
|
|
92
|
+
|
|
93
|
+
# --------------------------
|
|
94
|
+
# Elementwise ops (. *, ./, .^)
|
|
95
|
+
# --------------------------
|
|
96
|
+
|
|
97
|
+
def emul(self, other):
|
|
98
|
+
return M(self.A * _unwrap(other))
|
|
99
|
+
|
|
100
|
+
def ediv(self, other):
|
|
101
|
+
return M(self.A / _unwrap(other))
|
|
102
|
+
|
|
103
|
+
def epow(self, other):
|
|
104
|
+
return M(self.A ** _unwrap(other))
|
|
105
|
+
|
|
106
|
+
# --------------------------
|
|
107
|
+
# Linear algebra helpers
|
|
108
|
+
# --------------------------
|
|
109
|
+
|
|
110
|
+
def inv(self):
|
|
111
|
+
return M(np.linalg.inv(self.A))
|
|
112
|
+
|
|
113
|
+
def pinv(self):
|
|
114
|
+
return M(np.linalg.pinv(self.A))
|
|
115
|
+
|
|
116
|
+
def det(self):
|
|
117
|
+
return np.linalg.det(self.A)
|
|
118
|
+
|
|
119
|
+
def rank(self):
|
|
120
|
+
return np.linalg.matrix_rank(self.A)
|
|
121
|
+
|
|
122
|
+
def eig(self):
|
|
123
|
+
w, v = np.linalg.eig(self.A)
|
|
124
|
+
return M(w), M(v)
|
|
125
|
+
|
|
126
|
+
# --------------------------
|
|
127
|
+
# Concatenation
|
|
128
|
+
# --------------------------
|
|
129
|
+
|
|
130
|
+
@staticmethod
|
|
131
|
+
def hcat(*args):
|
|
132
|
+
return M(np.hstack([_unwrap(a) for a in args]))
|
|
133
|
+
|
|
134
|
+
@staticmethod
|
|
135
|
+
def vcat(*args):
|
|
136
|
+
return M(np.vstack([_unwrap(a) for a in args]))
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
# --------------------------
|
|
140
|
+
# MATLAB-style constructors
|
|
141
|
+
# --------------------------
|
|
142
|
+
|
|
143
|
+
def zeros(*shape):
|
|
144
|
+
return M(np.zeros(shape))
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def ones(*shape):
|
|
148
|
+
return M(np.ones(shape))
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def eye(n):
|
|
152
|
+
return M(np.eye(n))
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def rand(*shape):
|
|
156
|
+
return M(np.random.rand(*shape))
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def linspace(a, b, n=100):
|
|
160
|
+
return M(np.linspace(a, b, n))
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def diag(v):
|
|
164
|
+
return M(np.diag(_unwrap(v)))
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
# --------------------------
|
|
168
|
+
# MATLAB-like matrix literal
|
|
169
|
+
# --------------------------
|
|
170
|
+
|
|
171
|
+
def mat(expr: str) -> M:
|
|
172
|
+
"""
|
|
173
|
+
MATLAB-style matrix literal:
|
|
174
|
+
|
|
175
|
+
mat("1 2 3; 4 5 6")
|
|
176
|
+
mat("1,2,3;4,5,6")
|
|
177
|
+
|
|
178
|
+
Supports:
|
|
179
|
+
- spaces or commas as column separators
|
|
180
|
+
- semicolon or newline as row separators
|
|
181
|
+
"""
|
|
182
|
+
rows = expr.strip().replace("\n", ";").split(";")
|
|
183
|
+
data = []
|
|
184
|
+
for r in rows:
|
|
185
|
+
r = r.strip()
|
|
186
|
+
if not r:
|
|
187
|
+
continue
|
|
188
|
+
cols = [float(x) for x in r.replace(",", " ").split()]
|
|
189
|
+
data.append(cols)
|
|
190
|
+
return M(data)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
# --------------------------
|
|
194
|
+
# Utilities
|
|
195
|
+
# --------------------------
|
|
196
|
+
|
|
197
|
+
def _unwrap(x):
|
|
198
|
+
return x.A if isinstance(x, M) else x
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
# --------------------------
|
|
202
|
+
# Example usage
|
|
203
|
+
# --------------------------
|
|
204
|
+
|
|
205
|
+
if __name__ == "__main__":
|
|
206
|
+
A = mat("1 2; 3 4")
|
|
207
|
+
B = mat("5 6; 7 8")
|
|
208
|
+
|
|
209
|
+
print("A =", A)
|
|
210
|
+
print("B =", B)
|
|
211
|
+
|
|
212
|
+
print("A * B =", A * B)
|
|
213
|
+
print("A .* B =", A.emul(B))
|
|
214
|
+
print("A^2 =", A ** 2)
|
|
215
|
+
print("inv(A) =", A.inv())
|
|
216
|
+
print("A(1,2) =", A(1, 2))
|
|
217
|
+
|
|
218
|
+
C = M.hcat(A, B)
|
|
219
|
+
D = M.vcat(A, B)
|
|
220
|
+
|
|
221
|
+
print("[A B] =", C)
|
|
222
|
+
print("[A; B] =", D)
|
|
File without changes
|
|
File without changes
|