subsetmatrix 0.1.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lucas Dornelles Cherobim
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,671 @@
1
+ Metadata-Version: 2.4
2
+ Name: subsetmatrix
3
+ Version: 0.1.0
4
+ Summary: Generate, select, and materialize subset membership matrices from observation sets.
5
+ Author: Lucas Dornelles Cherobim
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/EngDornelles/subsetMatrix
8
+ Project-URL: Repository, https://github.com/EngDornelles/subsetMatrix
9
+ Project-URL: Issues, https://github.com/EngDornelles/subsetMatrix/issues
10
+ Keywords: subsets,combinations,matrix,numpy,combinatorics,dataset,mask
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Scientific/Engineering
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: numpy>=1.26
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=8; extra == "dev"
28
+ Dynamic: license-file
29
+
30
+ # subsetMatrix
31
+
32
+ `subsetMatrix` is a small Python library for generating, selecting, and materializing subsets from an observation set.
33
+
34
+ It starts with a simple idea:
35
+
36
+ > Given `n` observations, generate a binary matrix where each row represents one subset.
37
+
38
+ Each column represents one observation.
39
+ Each row represents one subset.
40
+ A value of `1` means the observation belongs to that subset.
41
+ A value of `0` means it does not.
42
+
43
+ For `n = 3`, the generated matrix is:
44
+
45
+ ```text
46
+ [[1 0 0]
47
+ [0 1 0]
48
+ [0 0 1]
49
+ [1 1 0]
50
+ [1 0 1]
51
+ [0 1 1]]
52
+ ```
53
+
54
+ The empty subset `[0 0 0]` and the full subset `[1 1 1]` are excluded by default.
55
+
56
+ ---
57
+
58
+ ## Why this exists
59
+
60
+ Many workflows need to explore combinations of observations, points, features, candidates, or records.
61
+
62
+ `subsetMatrix` provides a deterministic substrate for that kind of work.
63
+
64
+ It can be useful for:
65
+
66
+ * combinatorial analysis;
67
+ * subset generation;
68
+ * fixed-size subset selection;
69
+ * dataset slicing;
70
+ * candidate generation;
71
+ * research prototypes;
72
+ * model experimentation;
73
+ * matrix-based workflows;
74
+ * observation-subset analysis.
75
+
76
+ The library intentionally keeps interpretation out of the core.
77
+
78
+ It does not decide what a subset means.
79
+ It only helps generate, select, and materialize subsets.
80
+
81
+ ---
82
+
83
+ ## Core behavior
84
+
85
+ For `n` observations, there are:
86
+
87
+ ```text
88
+ 2^n
89
+ ```
90
+
91
+ possible subsets.
92
+
93
+ `subsetMatrix` excludes the empty and full subsets, so the generated matrix has:
94
+
95
+ ```text
96
+ 2^n - 2
97
+ ```
98
+
99
+ rows.
100
+
101
+ The matrix shape is:
102
+
103
+ ```text
104
+ (2^n - 2, n)
105
+ ```
106
+
107
+ Examples:
108
+
109
+ ```text
110
+ n = 3 → 6 rows
111
+ n = 4 → 14 rows
112
+ n = 20 → 1,048,574 rows
113
+ ```
114
+
115
+ Rows are grouped by subset size `k`.
116
+
117
+ For `n = 4`, rows are ordered as:
118
+
119
+ ```text
120
+ k = 1 → subsets with one active observation
121
+ k = 2 → subsets with two active observations
122
+ k = 3 → subsets with three active observations
123
+ ```
124
+
125
+ The groups `k = 0` and `k = n` are skipped.
126
+
127
+ ---
128
+
129
+ ## Installation
130
+
131
+ Clone the repository:
132
+
133
+ ```bash
134
+ git clone https://github.com/EngDornelles/subsetMatrix.git
135
+ cd subsetMatrix
136
+ ```
137
+
138
+ Create a virtual environment.
139
+
140
+ On Windows PowerShell:
141
+
142
+ ```powershell
143
+ py -m venv .venv
144
+ .\.venv\Scripts\activate
145
+ ```
146
+
147
+ Install the package in editable mode:
148
+
149
+ ```powershell
150
+ py -m pip install -e .
151
+ ```
152
+
153
+ Install test dependencies:
154
+
155
+ ```powershell
156
+ py -m pip install pytest
157
+ ```
158
+
159
+ Run tests:
160
+
161
+ ```powershell
162
+ py -m pytest -v
163
+ ```
164
+
165
+ ---
166
+
167
+ ## Quick start
168
+
169
+ ### Generate a subset matrix
170
+
171
+ ```python
172
+ from subsetmatrix.engine import generateMatrix
173
+
174
+ matrix = generateMatrix(3)
175
+
176
+ print(matrix)
177
+ ```
178
+
179
+ By default (no `K` given), rows are grouped by k, skipping singletons
180
+ (k=1) and including the full set (k=n):
181
+
182
+ Output:
183
+
184
+ ```text
185
+ [[1 1 0]
186
+ [1 0 1]
187
+ [0 1 1]
188
+ [1 1 1]]
189
+ ```
190
+
191
+ To include singletons or restrict to specific subset sizes, pass `K`
192
+ explicitly:
193
+
194
+ ```python
195
+ matrix = generateMatrix(3, [1, 2, 3])
196
+ ```
197
+
198
+ ---
199
+
200
+ ## User-facing dataset workflow
201
+
202
+ The easiest way to use the library is through `ObservationSet`.
203
+
204
+ ```python
205
+ from subsetmatrix.dataset_payload import ObservationSet
206
+
207
+ obs = ObservationSet(
208
+ {
209
+ "Y": [10, 20, 30, 40],
210
+ "X": ["A", "B", "C", "D"],
211
+ }
212
+ )
213
+
214
+ subsets = obs.get_subsets(2)
215
+
216
+ print(subsets)
217
+ ```
218
+
219
+ Output:
220
+
221
+ ```python
222
+ [
223
+ [["A", 10], ["B", 20]],
224
+ [["A", 10], ["C", 30]],
225
+ [["B", 20], ["C", 30]],
226
+ [["A", 10], ["D", 40]],
227
+ [["B", 20], ["D", 40]],
228
+ [["C", 30], ["D", 40]],
229
+ ]
230
+ ```
231
+
232
+ `X` contains labels.
233
+ `Y` contains observations.
234
+
235
+ If `X` is not provided, labels are generated automatically.
236
+
237
+ ```python
238
+ obs = ObservationSet(
239
+ {
240
+ "Y": [10, 20, 30, 40],
241
+ }
242
+ )
243
+
244
+ print(obs.X)
245
+ ```
246
+
247
+ Output:
248
+
249
+ ```python
250
+ [1, 2, 3, 4]
251
+ ```
252
+
253
+ By default, generated labels are one-based.
254
+
255
+ To use zero-based labels:
256
+
257
+ ```python
258
+ obs = ObservationSet(
259
+ {
260
+ "Y": [10, 20, 30, 40],
261
+ },
262
+ indexing_as_one=False,
263
+ )
264
+
265
+ print(obs.X)
266
+ ```
267
+
268
+ Output:
269
+
270
+ ```python
271
+ [0, 1, 2, 3]
272
+ ```
273
+
274
+ ---
275
+
276
+ ## Selecting subset windows by `k`
277
+
278
+ You can extract only the rows for a specific subset size.
279
+
280
+ `extract_k_window` computes row offsets assuming `matrix` was built
281
+ with the full k=1..n-1 sweep, so pass that explicit `K` to
282
+ `generateMatrix` — its own default (no `K`) skips k=1 and includes
283
+ k=n, which no longer matches those offsets. If you just want specific
284
+ k-sized subsets, prefer calling `generateMatrix(n, K)` directly (see
285
+ above) instead of going through `extract_k_window`.
286
+
287
+ ```python
288
+ from subsetmatrix.engine import generateMatrix
289
+ from subsetmatrix.selecting_subsets import extract_k_window
290
+
291
+ matrix = generateMatrix(4, list(range(1, 4)))
292
+
293
+ k2_matrix = extract_k_window(matrix, 2)
294
+
295
+ print(k2_matrix)
296
+ ```
297
+
298
+ Output:
299
+
300
+ ```text
301
+ [[1 1 0 0]
302
+ [1 0 1 0]
303
+ [0 1 1 0]
304
+ [1 0 0 1]
305
+ [0 1 0 1]
306
+ [0 0 1 1]]
307
+ ```
308
+
309
+ You can also extract multiple `k` groups:
310
+
311
+ ```python
312
+ selected = extract_k_window(matrix, [1, 3])
313
+ ```
314
+
315
+ The list is normalized, sorted, and deduplicated.
316
+
317
+ So this:
318
+
319
+ ```python
320
+ extract_k_window(matrix, [3, 1, 1])
321
+ ```
322
+
323
+ behaves like:
324
+
325
+ ```python
326
+ extract_k_window(matrix, [1, 3])
327
+ ```
328
+
329
+ ---
330
+
331
+ ## Fixed-size mask generation
332
+
333
+ `subsetMatrix` uses integer masks internally to generate subset rows.
334
+
335
+ You can generate masks directly for a fixed subset size `k`:
336
+
337
+ ```python
338
+ from subsetmatrix.engine import iter_k_masks
339
+
340
+ for mask in iter_k_masks(n=4, k=2):
341
+ print(mask)
342
+ ```
343
+
344
+ Output:
345
+
346
+ ```text
347
+ 3
348
+ 5
349
+ 6
350
+ 9
351
+ 10
352
+ 12
353
+ ```
354
+
355
+ Those masks correspond to:
356
+
357
+ ```text
358
+ 0011
359
+ 0101
360
+ 0110
361
+ 1001
362
+ 1010
363
+ 1100
364
+ ```
365
+
366
+ Each mask has exactly two active bits.
367
+
368
+ ---
369
+
370
+ ## Cardinality
371
+
372
+ You can check how many active observations a mask contains:
373
+
374
+ ```python
375
+ from subsetmatrix.engine import cardinality
376
+
377
+ print(cardinality(5))
378
+ ```
379
+
380
+ Output:
381
+
382
+ ```text
383
+ 2
384
+ ```
385
+
386
+ Because:
387
+
388
+ ```text
389
+ 5 = 0101
390
+ ```
391
+
392
+ has two active bits.
393
+
394
+ ---
395
+
396
+ ## Current API
397
+
398
+ ### `generateMatrix(n: int, K: list[int] = [])`
399
+
400
+ Generates the subset membership matrix for the requested subset sizes,
401
+ grouped by k. If `K` is omitted, defaults to `range(2, n + 1)` —
402
+ singletons (k=1) are skipped and the full set (k=n) is included.
403
+
404
+ ```python
405
+ from subsetmatrix.engine import generateMatrix
406
+
407
+ matrix = generateMatrix(4)
408
+ ```
409
+
410
+ For `n = 4`, the shape is:
411
+
412
+ ```text
413
+ (11, 4)
414
+ ```
415
+
416
+ Pass `K` explicitly to select specific subset sizes:
417
+
418
+ ```python
419
+ matrix = generateMatrix(4, [2]) # only pairs
420
+ matrix = generateMatrix(4, [1, 2, 3]) # the pre-1.0 default: full k=1..n-1 sweep
421
+ ```
422
+
423
+ ---
424
+
425
+ ### `iter_k_masks(n: int, k: int)`
426
+
427
+ Yields integer masks with exactly `k` active observations.
428
+
429
+ ```python
430
+ from subsetmatrix.engine import iter_k_masks
431
+
432
+ masks = list(iter_k_masks(4, 2))
433
+ ```
434
+
435
+ ---
436
+
437
+ ### `cardinality(mask: int)`
438
+
439
+ Returns how many active bits exist in a mask.
440
+
441
+ ```python
442
+ from subsetmatrix.engine import cardinality
443
+
444
+ cardinality(12)
445
+ ```
446
+
447
+ ---
448
+
449
+ ### `extract_k_window(matrix, k)`
450
+
451
+ Extracts rows for one or more subset sizes.
452
+
453
+ ```python
454
+ from subsetmatrix.selecting_subsets import extract_k_window
455
+
456
+ k2 = extract_k_window(matrix, 2)
457
+ mixed = extract_k_window(matrix, [1, 3])
458
+ ```
459
+
460
+ ---
461
+
462
+ ### `ObservationSet(points).get_subsets(k)`
463
+
464
+ Materializes actual dataset subsets.
465
+
466
+ ```python
467
+ from subsetmatrix.dataset_payload import ObservationSet
468
+
469
+ obs = ObservationSet(
470
+ {
471
+ "Y": [10, 20, 30, 40],
472
+ "X": ["A", "B", "C", "D"],
473
+ }
474
+ )
475
+
476
+ obs.get_subsets(2)
477
+ ```
478
+
479
+ ---
480
+
481
+ ## Repository structure
482
+
483
+ ```text
484
+ subsetMatrix/
485
+ ├── LICENSE
486
+ ├── README.md
487
+ ├── pyproject.toml
488
+ ├── src/
489
+ │ └── subsetmatrix/
490
+ │ ├── __init__.py
491
+ │ ├── engine.py
492
+ │ ├── selecting_subsets.py
493
+ │ └── dataset_payload.py
494
+ └── tests/
495
+ ├── test_engine.py
496
+ ├── test_selecting_subsets.py
497
+ └── test_dataset_payload.py
498
+ ```
499
+
500
+ ---
501
+
502
+ ## Design notes
503
+
504
+ ### Matrix generation
505
+
506
+ The generated matrix is a binary membership matrix.
507
+
508
+ Each row is a subset.
509
+ Each column is an observation.
510
+
511
+ Example:
512
+
513
+ ```text
514
+ [1 0 1 0]
515
+ ```
516
+
517
+ means:
518
+
519
+ ```text
520
+ include observation 0
521
+ exclude observation 1
522
+ include observation 2
523
+ exclude observation 3
524
+ ```
525
+
526
+ ---
527
+
528
+ ### Cardinality grouping
529
+
530
+ Rows are grouped by subset size `k`.
531
+
532
+ This makes it possible to extract all subsets of a specific size without scanning the whole matrix.
533
+
534
+ For example, if you only need subsets with `k = 3`, you can extract only that window.
535
+
536
+ ---
537
+
538
+ ### Empty and full subsets
539
+
540
+ The empty subset and full subset are excluded.
541
+
542
+ They are usually not useful for workflows where subsets are being compared, sampled, scored, or transformed.
543
+
544
+ Excluded rows:
545
+
546
+ ```text
547
+ [0 0 0 ... 0]
548
+ [1 1 1 ... 1]
549
+ ```
550
+
551
+ ---
552
+
553
+ ### Dense matrix warning
554
+
555
+ The full dense matrix grows quickly.
556
+
557
+ ```text
558
+ n = 20 → 1,048,574 rows
559
+ n = 26 → 67,108,862 rows
560
+ ```
561
+
562
+ Future versions may add:
563
+
564
+ * mask-only output;
565
+ * chunked generation;
566
+ * memory estimation;
567
+ * packed storage;
568
+ * optional export formats;
569
+ * lazy payload materialization.
570
+
571
+ The current version prioritizes clarity and deterministic behavior.
572
+
573
+ ---
574
+
575
+ ## Testing
576
+
577
+ Run:
578
+
579
+ ```powershell
580
+ py -m pytest -v
581
+ ```
582
+
583
+ Current test coverage validates:
584
+
585
+ * matrix shape;
586
+ * exact output for `n = 3`;
587
+ * cardinality grouping;
588
+ * exclusion of empty and full rows;
589
+ * invalid `n`;
590
+ * k-window extraction;
591
+ * sorted and deduplicated `k` lists;
592
+ * rejection of invalid `k`;
593
+ * NumPy integer support;
594
+ * dataset payload materialization;
595
+ * default generated labels;
596
+ * custom labels;
597
+ * invalid input handling.
598
+
599
+ Example current test result:
600
+
601
+ ```text
602
+ 18 passed
603
+ ```
604
+
605
+ ---
606
+
607
+ ## Development status
608
+
609
+ `subsetMatrix` is in early development.
610
+
611
+ Current stable layers:
612
+
613
+ ```text
614
+ engine.py
615
+ → generate subset matrix
616
+
617
+ selecting_subsets.py
618
+ → extract k-window slices
619
+
620
+ dataset_payload.py
621
+ → materialize dataset subsets
622
+ ```
623
+
624
+ Planned improvements may include:
625
+
626
+ * snake_case aliases;
627
+ * chunked matrix generation;
628
+ * mask-first public workflows;
629
+ * memory estimation helpers;
630
+ * optional pandas helpers;
631
+ * optional export utilities;
632
+ * expanded documentation;
633
+ * performance benchmarks.
634
+
635
+ ---
636
+
637
+ ## Naming
638
+
639
+ The GitHub repository is named:
640
+
641
+ ```text
642
+ subsetMatrix
643
+ ```
644
+
645
+ The Python package is imported as:
646
+
647
+ ```python
648
+ import subsetmatrix
649
+ ```
650
+
651
+ This follows Python package naming conventions while preserving the repository’s public name.
652
+
653
+ ---
654
+
655
+ ## License
656
+
657
+ This project is licensed under the MIT License.
658
+
659
+ See:
660
+
661
+ ```text
662
+ LICENSE
663
+ ```
664
+
665
+ ---
666
+
667
+ ## Author
668
+
669
+ Created by Lucas Dornelles Cherobim.
670
+
671
+ GitHub: [EngDornelles](https://github.com/EngDornelles)