numox 1.0.0__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.
numox-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,57 @@
1
+ Metadata-Version: 2.4
2
+ Name: numox
3
+ Version: 1.0.0
4
+ Summary: A high-performance C Extension for matrix math
5
+ Author: oxoxox-oxox
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Dynamic: author
9
+ Dynamic: description
10
+ Dynamic: description-content-type
11
+ Dynamic: requires-python
12
+ Dynamic: summary
13
+
14
+ # numox
15
+
16
+ A high-performance Python C-extension for matrix mathematics, accelerated with OpenMP, AVX, and FMA instructions.
17
+
18
+ ## Installation
19
+
20
+ ### From Source (Requires C compiler)
21
+
22
+ You can install `numox` directly from this GitHub repository:
23
+
24
+ ```bash
25
+ # Note: Ensure you have a C compiler (GCC/Clang) with OpenMP support installed.
26
+ pip install git https://github.com/YourUsername/numox.git
27
+ ```
28
+
29
+ ### Docker Development Environment
30
+
31
+ If you want a clean, "painless" environment to compile and test the C-extension without configuring your local machine, use the provided Ubuntu 22.04 Dockerfile:
32
+
33
+ ```bash
34
+ # 1. Build the docker image
35
+ docker build -t numox-env .
36
+
37
+ # 2. Run the container, mounting your current code directory
38
+ docker run -it --rm -v "${PWD}:/workspace" numox-env bash
39
+
40
+ # 3. Inside the container, install the library or run tests
41
+ pip install .
42
+ make test
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ```python
48
+ import numox as nc
49
+
50
+ # Create a 3x3 matrix initialized with random values between 0.0 and 1.0
51
+ mat1 = nc.Matrix(3, 3, rand=True, low=0.0, high=1.0)
52
+ mat2 = nc.Matrix(3, 3, rand=True, low=0.0, high=1.0)
53
+
54
+ # Perform fast matrix operations
55
+ result = mat1 + mat2
56
+ print(result.to_list())
57
+ ```
numox-1.0.0/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # numox
2
+
3
+ A high-performance Python C-extension for matrix mathematics, accelerated with OpenMP, AVX, and FMA instructions.
4
+
5
+ ## Installation
6
+
7
+ ### From Source (Requires C compiler)
8
+
9
+ You can install `numox` directly from this GitHub repository:
10
+
11
+ ```bash
12
+ # Note: Ensure you have a C compiler (GCC/Clang) with OpenMP support installed.
13
+ pip install git https://github.com/YourUsername/numox.git
14
+ ```
15
+
16
+ ### Docker Development Environment
17
+
18
+ If you want a clean, "painless" environment to compile and test the C-extension without configuring your local machine, use the provided Ubuntu 22.04 Dockerfile:
19
+
20
+ ```bash
21
+ # 1. Build the docker image
22
+ docker build -t numox-env .
23
+
24
+ # 2. Run the container, mounting your current code directory
25
+ docker run -it --rm -v "${PWD}:/workspace" numox-env bash
26
+
27
+ # 3. Inside the container, install the library or run tests
28
+ pip install .
29
+ make test
30
+ ```
31
+
32
+ ## Quick Start
33
+
34
+ ```python
35
+ import numox as nc
36
+
37
+ # Create a 3x3 matrix initialized with random values between 0.0 and 1.0
38
+ mat1 = nc.Matrix(3, 3, rand=True, low=0.0, high=1.0)
39
+ mat2 = nc.Matrix(3, 3, rand=True, low=0.0, high=1.0)
40
+
41
+ # Perform fast matrix operations
42
+ result = mat1 + mat2
43
+ print(result.to_list())
44
+ ```
numox-1.0.0/matrix.c ADDED
@@ -0,0 +1,371 @@
1
+ #include "matrix.h"
2
+ #include <stddef.h>
3
+ #include <stdio.h>
4
+ #include <stdlib.h>
5
+ #include <omp.h>
6
+
7
+ // Include SSE intrinsics
8
+ #if defined(_MSC_VER)
9
+ #include <intrin.h>
10
+ #elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
11
+ #include <immintrin.h>
12
+ #include <x86intrin.h>
13
+ #endif
14
+
15
+ /* Below are some intel intrinsics that might be useful
16
+ * void _mm256_storeu_pd (double * mem_addr, __m256d a)
17
+ * __m256d _mm256_set1_pd (double a)
18
+ * __m256d _mm256_set_pd (double e3, double e2, double e1, double e0)
19
+ * __m256d _mm256_loadu_pd (double const * mem_addr)
20
+ * __m256d _mm256_add_pd (__m256d a, __m256d b)
21
+ * __m256d _mm256_sub_pd (__m256d a, __m256d b)
22
+ * __m256d _mm256_fmadd_pd (__m256d a, __m256d b, __m256d c)
23
+ * __m256d _mm256_mul_pd (__m256d a, __m256d b)
24
+ * __m256d _mm256_cmp_pd (__m256d a, __m256d b, const int imm8)
25
+ * __m256d _mm256_and_pd (__m256d a, __m256d b)
26
+ * __m256d _mm256_max_pd (__m256d a, __m256d b)
27
+ */
28
+
29
+ /*
30
+ * Generates a random double between `low` and `high`.
31
+ */
32
+ double rand_double(double low, double high)
33
+ {
34
+ double range = (high - low);
35
+ double div = RAND_MAX / range;
36
+ return low + (rand() / div);
37
+ }
38
+
39
+ /*
40
+ * Generates a random matrix with `seed`.
41
+ */
42
+ void rand_matrix(matrix *result, unsigned int seed, double low, double high)
43
+ {
44
+ srand(seed);
45
+ for (int i = 0; i < result->rows; i++)
46
+ {
47
+ for (int j = 0; j < result->cols; j++)
48
+ {
49
+ set(result, i, j, rand_double(low, high));
50
+ }
51
+ }
52
+ }
53
+
54
+ /*
55
+ *Allocate space for matrix, init all the element in the matrix to 0
56
+ */
57
+ int allocate_matrix(matrix **mat, int rows, int cols)
58
+ {
59
+ if (mat == NULL || rows <= 0 || cols <= 0)
60
+ {
61
+ return -1;
62
+ }
63
+
64
+ matrix *m = malloc(sizeof(matrix));
65
+ if (m == NULL)
66
+ {
67
+ free(m);
68
+ return -1;
69
+ }
70
+ m->rows = rows;
71
+ m->cols = cols;
72
+ m->is_1d = rows == 1 || cols == 1;
73
+ m->ref_cnt = 1;
74
+ m->data = malloc(rows * sizeof(double *));
75
+ m->parent = NULL;
76
+
77
+ if (m->data == NULL)
78
+ {
79
+ free(m->data);
80
+ free(m);
81
+ return -1;
82
+ }
83
+
84
+ for (int i = 0; i < rows; i++)
85
+ {
86
+ m->data[i] = malloc(cols * sizeof(double));
87
+ if (m->data[i] == NULL)
88
+ {
89
+ for (int j = 0; j <= i; j++)
90
+ {
91
+ free(m->data[j]);
92
+ }
93
+ free(m->data);
94
+ free(m);
95
+ return -1;
96
+ }
97
+ for (int j = 0; j < cols; j++)
98
+ {
99
+ m->data[i][j] = 0.0;
100
+ }
101
+ }
102
+
103
+ *mat = m;
104
+
105
+ return 0;
106
+ }
107
+
108
+ /*
109
+ *allocate space for ref of one existing matrix
110
+ */
111
+ int allocate_matrix_ref(matrix **mat, matrix *from, int row_offset, int col_offset,
112
+ int rows, int cols)
113
+ {
114
+ matrix *m = malloc(sizeof(matrix));
115
+ if (m == NULL || rows < 1 || cols < 1)
116
+ {
117
+ free(m);
118
+ return -1;
119
+ }
120
+
121
+ m->rows = rows;
122
+ m->cols = cols;
123
+ m->is_1d = rows == 1 || cols == 1;
124
+ m->ref_cnt = 0;
125
+ m->parent = from;
126
+
127
+ m->data = malloc(rows * sizeof(double *));
128
+ if (m->data == NULL)
129
+ {
130
+ free(m->data);
131
+ free(m);
132
+ return -1;
133
+ }
134
+
135
+ for (int i = 0; i < rows; i++)
136
+ {
137
+ m->data[i] = from->data[row_offset + i] + col_offset;
138
+ }
139
+
140
+ from->ref_cnt += 1;
141
+
142
+ *mat = m;
143
+ return 0;
144
+ }
145
+
146
+ /*
147
+ *deallocate the matrix, also allocate the father of the matrix if it exist
148
+ */
149
+ void deallocate_matrix(matrix *mat)
150
+ {
151
+ if (mat == NULL)
152
+ {
153
+ return;
154
+ }
155
+
156
+ mat->ref_cnt -= 1;
157
+
158
+ if (mat->ref_cnt > 0)
159
+ {
160
+ return;
161
+ }
162
+
163
+ if (mat->parent == NULL)
164
+ {
165
+ for (int i = 0; i < mat->rows; i++)
166
+ {
167
+ free(mat->data[i]);
168
+ }
169
+ }
170
+ else
171
+ {
172
+ deallocate_matrix(mat->parent);
173
+ }
174
+
175
+ free(mat->data);
176
+ free(mat);
177
+ }
178
+
179
+ /*
180
+ * Return the double value of the matrix at the given row and column.
181
+ */
182
+ double get(matrix *mat, int row, int col)
183
+ {
184
+ return mat->data[row][col];
185
+ }
186
+
187
+ /*
188
+ * Set the value at the given row and column to val.
189
+ */
190
+ void set(matrix *mat, int row, int col, double val)
191
+ {
192
+ mat->data[row][col] = val;
193
+ }
194
+
195
+ /*
196
+ * Set all entries in mat to val
197
+ */
198
+ void fill_matrix(matrix *mat, double val)
199
+ {
200
+ for (int i = 0; i < mat->rows; i++)
201
+ {
202
+ for (int j = 0; j < mat->cols; j++)
203
+ {
204
+ mat->data[i][j] = val;
205
+ }
206
+ }
207
+ }
208
+
209
+ /*
210
+ * Store the result of adding mat1 and mat2 to `result`.
211
+ * Return 0 upon success and a -1 value upon failure.
212
+ */
213
+ int add_matrix(matrix *result, matrix *mat1, matrix *mat2)
214
+ {
215
+ if (mat1->rows != mat2->rows || mat1->cols != mat2->cols)
216
+ {
217
+ return -1;
218
+ }
219
+
220
+ int row = mat1->rows;
221
+ int col = mat2->cols;
222
+
223
+ for (int i = 0; i < row; i++)
224
+ {
225
+ for (int j = 0; j < col; j++)
226
+ {
227
+ result->data[i][j] = mat1->data[i][j] + mat2->data[i][j];
228
+ }
229
+ }
230
+
231
+ return 0;
232
+ }
233
+
234
+ /*
235
+ * Store the result of subtracting mat2 from mat1 to `result`.
236
+ * Return 0 upon success and a -1 value upon failure.
237
+ */
238
+ int sub_matrix(matrix *result, matrix *mat1, matrix *mat2)
239
+ {
240
+ if (mat1->rows != mat2->rows || mat1->cols != mat2->cols)
241
+ {
242
+ return -1;
243
+ }
244
+
245
+ int row = mat1->rows;
246
+ int col = mat2->cols;
247
+
248
+ for (int i = 0; i < row; i++)
249
+ {
250
+ for (int j = 0; j < col; j++)
251
+ {
252
+ result->data[i][j] = mat1->data[i][j] - mat2->data[i][j];
253
+ }
254
+ }
255
+
256
+ return 0;
257
+ }
258
+
259
+ /*
260
+ * Store the result of multiplying mat1 and mat2 to `result`.
261
+ * Return 0 upon success and a -1 value upon failure.
262
+ */
263
+ int mul_matrix(matrix *result, matrix *mat1, matrix *mat2)
264
+ {
265
+ int row1 = mat1->rows;
266
+ int row2 = mat2->rows;
267
+ int col1 = mat1->cols;
268
+ int col2 = mat2->cols;
269
+
270
+ if (col1 != row2)
271
+ {
272
+ return -1;
273
+ }
274
+
275
+ for (int i = 0; i < row1; i++)
276
+ {
277
+ for (int j = 0; j < col2; j++)
278
+ {
279
+ double sum = 0.0;
280
+ for (int k = 0; k < col1; k++)
281
+ {
282
+ sum += mat1->data[i][k] * mat2->data[k][j];
283
+ }
284
+
285
+ result->data[i][j] = sum;
286
+ }
287
+ }
288
+
289
+ return 0;
290
+ }
291
+
292
+ /*
293
+ * Store the result of raising mat to the (pow)th power to `result`.
294
+ * Return 0 upon success and a -1 value upon failure.
295
+ */
296
+ int pow_matrix(matrix *result, matrix *mat, int pow)
297
+ {
298
+ matrix *template;
299
+ allocate_matrix(&template, mat->rows, mat->cols);
300
+
301
+ for (int r = 0; r < mat->rows; r++)
302
+ {
303
+ for (int c = 0; c < mat->cols; c++)
304
+ {
305
+ result->data[r][c] = mat->data[r][c];
306
+ }
307
+ }
308
+
309
+ // 循环 pow - 1 次
310
+ for (int step = 0; step < pow - 1; step++)
311
+ {
312
+ // 拿当前的 result 去乘 mat,算好的结果丢进安全的 template 里
313
+ mul_matrix(template, result, mat);
314
+
315
+ // 把最新结果从 template 拷回 result
316
+ for (int r = 0; r < mat->rows; r++)
317
+ {
318
+ for (int c = 0; c < mat->cols; c++)
319
+ {
320
+ result->data[r][c] = template->data[r][c];
321
+ }
322
+ }
323
+ }
324
+
325
+ deallocate_matrix(template);
326
+ return 0;
327
+ }
328
+
329
+ /*
330
+ * Store the result of element-wise negating mat's entries to `result`.
331
+ * Return 0 upon success and a -1 value upon failure.
332
+ */
333
+ int neg_matrix(matrix *result, matrix *mat)
334
+ {
335
+ int row = mat->rows;
336
+ int col = mat->cols;
337
+
338
+ for (int i = 0; i < row; i++)
339
+ {
340
+ for (int j = 0; j < col; j++)
341
+ {
342
+ double num = mat->data[i][j];
343
+ result->data[i][j] = -1 * num;
344
+ }
345
+ }
346
+ return 0;
347
+ }
348
+
349
+ /*
350
+ * Store the result of taking the absolute value element-wise to `result`.
351
+ * Return 0 upon success and a -1 value upon failure.
352
+ */
353
+ int abs_matrix(matrix *result, matrix *mat)
354
+ {
355
+ int row = mat->rows;
356
+ int col = mat->cols;
357
+
358
+ for (int i = 0; i < row; i++)
359
+ {
360
+ for (int j = 0; j < col; j++)
361
+ {
362
+ double num = mat->data[i][j];
363
+ if (num <= 0)
364
+ {
365
+ num = -num;
366
+ }
367
+ result->data[i][j] = num;
368
+ }
369
+ }
370
+ return 0;
371
+ }