binsparse 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.
binsparse/tensor.py ADDED
@@ -0,0 +1,577 @@
1
+ """In-memory representations and container parsing for Binsparse tensors."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from abc import ABC, abstractmethod
6
+ from dataclasses import dataclass
7
+ from typing import Any, ClassVar
8
+
9
+ import numpy as np
10
+
11
+ from .container import BinsparseContainer
12
+ from .errors import BinsparseParseError
13
+ from .version import BINSPARSE_VERSION, check_binsparse_version
14
+
15
+
16
+ class BinsparseLevel:
17
+ level_desc: ClassVar[str]
18
+
19
+
20
+ @dataclass
21
+ class IndexableLevel(BinsparseLevel):
22
+ rank: int
23
+
24
+ def __post_init__(self) -> None:
25
+ if self.rank < 1:
26
+ raise ValueError("an indexable level must have rank >= 1")
27
+
28
+
29
+ @dataclass
30
+ class ElementLevel(BinsparseLevel):
31
+ values: np.ndarray
32
+ level_desc: ClassVar[str] = "element"
33
+ rank: ClassVar[int] = 0
34
+
35
+
36
+ @dataclass
37
+ class DenseLevel(IndexableLevel):
38
+ level: BinsparseLevel
39
+ level_desc: ClassVar[str] = "dense"
40
+
41
+
42
+ @dataclass
43
+ class SparseLevel(IndexableLevel):
44
+ level: BinsparseLevel
45
+ indices: tuple[np.ndarray, ...]
46
+ pointers_to_next: np.ndarray | None = None
47
+ level_desc: ClassVar[str] = "sparse"
48
+
49
+ def __post_init__(self) -> None:
50
+ super().__post_init__()
51
+ if len(self.indices) != self.rank:
52
+ raise ValueError("the number of indices arrays must equal rank")
53
+
54
+
55
+ @dataclass
56
+ class BinsparseTensor(ABC):
57
+ shape: tuple[int, ...]
58
+ number_of_stored_values: int
59
+ fill: bool | None = None
60
+ fill_value: Any = None
61
+
62
+ version: ClassVar[str] = BINSPARSE_VERSION
63
+ format: ClassVar[str]
64
+
65
+ def __post_init__(self) -> None:
66
+ self.shape = tuple(self.shape)
67
+ if any(size < 0 for size in self.shape):
68
+ raise ValueError("shape dimensions must be non-negative")
69
+ if self.number_of_stored_values < 0:
70
+ raise ValueError("number_of_stored_values must be non-negative")
71
+ if self.fill is not True and self.fill_value is not None:
72
+ raise ValueError("fill_value requires fill=True")
73
+
74
+ @classmethod
75
+ def parse(
76
+ cls,
77
+ container: BinsparseContainer,
78
+ *,
79
+ alias: bool | None = None,
80
+ copy: bool | None = None,
81
+ ) -> BinsparseTensor:
82
+ """Parse a tensor and all required arrays from *container*."""
83
+ header = container.read_header()
84
+ required = ("version", "format", "shape", "number_of_stored_values")
85
+ missing = next((key for key in required if key not in header), None)
86
+ if missing is not None:
87
+ raise BinsparseParseError(f"missing required descriptor key {missing!r}")
88
+ check_binsparse_version(header["version"])
89
+ format_name = header["format"]
90
+ try:
91
+ if hasattr(cls, "format"):
92
+ if cls.format != format_name:
93
+ raise BinsparseParseError(
94
+ f"descriptor format {format_name!r} cannot be parsed as "
95
+ f"{cls.__name__}"
96
+ )
97
+ tensor_cls = cls
98
+ elif alias is False:
99
+ tensor_cls = CustomTensor
100
+ elif alias is True and format_name == "custom":
101
+ alias_name = _custom_alias(header)
102
+ tensor_cls = (
103
+ CustomTensor
104
+ if alias_name is None
105
+ else _FORMAT_CLASSES[alias_name]
106
+ )
107
+ else:
108
+ tensor_cls = _FORMAT_CLASSES[format_name]
109
+ except KeyError as error:
110
+ raise BinsparseParseError(f"unrecognized format {format_name!r}") from error
111
+ common: dict[str, Any] = {
112
+ "shape": tuple(header["shape"]),
113
+ "number_of_stored_values": header["number_of_stored_values"],
114
+ "fill": header.get("fill"),
115
+ }
116
+ if common["fill"] is True:
117
+ fill = container.read_buffer("fill_value", 1, copy=copy)
118
+ if fill.size != 1:
119
+ raise BinsparseParseError("fill_value must contain exactly one value")
120
+ common["fill_value"] = fill.reshape(-1)[0]
121
+ return tensor_cls._parse(container, header, common, copy)
122
+
123
+ @classmethod
124
+ @abstractmethod
125
+ def _parse(
126
+ cls,
127
+ container: BinsparseContainer,
128
+ header: dict[str, Any],
129
+ common: dict[str, Any],
130
+ copy: bool | None,
131
+ ) -> BinsparseTensor:
132
+ """Parse format-specific data after shared metadata has been parsed."""
133
+
134
+ def serialize(
135
+ self,
136
+ container: BinsparseContainer,
137
+ *,
138
+ alias: bool | None = None,
139
+ copy: bool | None = None,
140
+ ) -> None:
141
+ """Write shared metadata, format-specific data, and the descriptor."""
142
+ header: dict[str, Any] = {
143
+ "version": BINSPARSE_VERSION,
144
+ "format": self.format,
145
+ "shape": list(self.shape),
146
+ "number_of_stored_values": self.number_of_stored_values,
147
+ }
148
+ if self.fill is not None:
149
+ header["fill"] = self.fill
150
+ if self.fill is True:
151
+ fill = np.asarray([self.fill_value])
152
+ container.write_buffer("fill_value", fill, copy=copy)
153
+ header.update(self._serialize(container, copy))
154
+ if alias is False and self.format != "custom":
155
+ descriptor, transpose = _PREDEFINED_LEVELS[self.format]
156
+ custom: dict[str, Any] = {"level": descriptor}
157
+ if transpose is not None:
158
+ custom["transpose"] = list(transpose)
159
+ header.update(format="custom", custom=custom)
160
+ elif alias is True and self.format == "custom":
161
+ alias_name = _custom_alias(header)
162
+ if alias_name is not None:
163
+ header["format"] = alias_name
164
+ header.pop("custom")
165
+ container.write_header(header)
166
+
167
+ @abstractmethod
168
+ def _serialize(
169
+ self,
170
+ container: BinsparseContainer,
171
+ copy: bool | None,
172
+ ) -> dict[str, Any]:
173
+ """Write format-specific arrays and return additional descriptor data."""
174
+
175
+
176
+ @dataclass
177
+ class CustomTensor(BinsparseTensor):
178
+ level: BinsparseLevel | None = None
179
+ transpose: tuple[int, ...] | None = None
180
+ format: ClassVar[str] = "custom"
181
+
182
+ def __post_init__(self) -> None:
183
+ super().__post_init__()
184
+ if self.level is None:
185
+ raise ValueError("a custom tensor requires a root level")
186
+ if self.transpose is not None:
187
+ dimensions = set(range(len(self.shape)))
188
+ if len(self.transpose) != len(self.shape) or set(self.transpose) != dimensions:
189
+ raise ValueError("transpose must be a permutation of the dimensions")
190
+ if self._level_rank(self.level) != len(self.shape):
191
+ raise ValueError("custom levels must consume exactly the tensor rank")
192
+
193
+ @staticmethod
194
+ def _level_rank(level: BinsparseLevel) -> int:
195
+ if isinstance(level, ElementLevel):
196
+ return 0
197
+ if isinstance(level, (DenseLevel, SparseLevel)):
198
+ return level.rank + CustomTensor._level_rank(level.level)
199
+ raise TypeError(f"unsupported level type {type(level).__name__}")
200
+
201
+ @classmethod
202
+ def _parse(
203
+ cls,
204
+ container: BinsparseContainer,
205
+ header: dict[str, Any],
206
+ common: dict[str, Any],
207
+ copy: bool | None,
208
+ ) -> BinsparseTensor:
209
+ format_name = header["format"]
210
+ if format_name == "custom":
211
+ try:
212
+ custom = header["custom"]
213
+ descriptor = custom["level"]
214
+ except (KeyError, TypeError) as error:
215
+ raise BinsparseParseError("custom format requires custom.level") from error
216
+ transpose = custom.get("transpose")
217
+ else:
218
+ try:
219
+ descriptor, transpose = _PREDEFINED_LEVELS[format_name]
220
+ except KeyError as error:
221
+ raise BinsparseParseError(f"unrecognized format {format_name!r}") from error
222
+ transpose_tuple = None if transpose is None else tuple(transpose)
223
+ level = cls._parse_level(container, header, descriptor, 0, copy)
224
+ return cls(
225
+ **common,
226
+ level=level,
227
+ transpose=transpose_tuple,
228
+ )
229
+
230
+ @staticmethod
231
+ def _parse_level(
232
+ container: BinsparseContainer,
233
+ header: dict[str, Any],
234
+ descriptor: dict[str, Any],
235
+ depth: int,
236
+ copy: bool | None,
237
+ ) -> BinsparseLevel:
238
+ try:
239
+ level_desc = descriptor["level_desc"]
240
+ except (KeyError, TypeError) as error:
241
+ raise BinsparseParseError("each custom level requires level_desc") from error
242
+ match level_desc:
243
+ case "element":
244
+ count = header["number_of_stored_values"]
245
+ return ElementLevel(container.read_buffer("values", count, copy=copy))
246
+ case "dense":
247
+ try:
248
+ rank = descriptor["rank"]
249
+ child_descriptor = descriptor["level"]
250
+ except KeyError as error:
251
+ raise BinsparseParseError(
252
+ f"dense level requires {error.args[0]!r}"
253
+ ) from error
254
+ if rank < 1:
255
+ raise BinsparseParseError("dense level rank must be >= 1")
256
+ child = CustomTensor._parse_level(
257
+ container,
258
+ header,
259
+ child_descriptor,
260
+ depth + rank,
261
+ copy,
262
+ )
263
+ return DenseLevel(rank, child)
264
+ case "sparse":
265
+ try:
266
+ rank = descriptor["rank"]
267
+ child_descriptor = descriptor["level"]
268
+ except KeyError as error:
269
+ raise BinsparseParseError(
270
+ f"sparse level requires {error.args[0]!r}"
271
+ ) from error
272
+ if rank < 1:
273
+ raise BinsparseParseError("sparse level rank must be >= 1")
274
+ pointers = (
275
+ None
276
+ if depth == 0
277
+ else container.read_buffer(f"pointers_to_{depth}", copy=copy)
278
+ )
279
+ indices = tuple(
280
+ container.read_buffer(f"indices_{dimension}", copy=copy)
281
+ for dimension in range(depth, depth + rank)
282
+ )
283
+ child = CustomTensor._parse_level(
284
+ container,
285
+ header,
286
+ child_descriptor,
287
+ depth + rank,
288
+ copy,
289
+ )
290
+ return SparseLevel(rank, child, indices, pointers)
291
+ case _:
292
+ raise BinsparseParseError(
293
+ f"unrecognized level descriptor {level_desc!r}"
294
+ )
295
+
296
+ def _serialize(
297
+ self,
298
+ container: BinsparseContainer,
299
+ copy: bool | None,
300
+ ) -> dict[str, Any]:
301
+ descriptor = self._serialize_level(container, self.level, 0, copy)
302
+ custom: dict[str, Any] = {"level": descriptor}
303
+ if self.transpose is not None:
304
+ custom["transpose"] = list(self.transpose)
305
+ return {"custom": custom}
306
+
307
+ @staticmethod
308
+ def _serialize_level(
309
+ container: BinsparseContainer,
310
+ level: BinsparseLevel | None,
311
+ depth: int,
312
+ copy: bool | None,
313
+ ) -> dict[str, Any]:
314
+ match level:
315
+ case ElementLevel(values):
316
+ container.write_buffer("values", np.asarray(values), copy=copy)
317
+ return {"level_desc": "element"}
318
+ case DenseLevel(rank, child_level):
319
+ child = CustomTensor._serialize_level(
320
+ container, child_level, depth + rank, copy
321
+ )
322
+ return {"level_desc": "dense", "rank": rank, "level": child}
323
+ case SparseLevel(rank, child_level, indices, pointers):
324
+ if depth > 0:
325
+ if pointers is None:
326
+ raise ValueError(
327
+ f"sparse level at depth {depth} requires pointers"
328
+ )
329
+ name = f"pointers_to_{depth}"
330
+ container.write_buffer(name, np.asarray(pointers), copy=copy)
331
+ for offset, index in enumerate(indices):
332
+ name = f"indices_{depth + offset}"
333
+ container.write_buffer(name, np.asarray(index), copy=copy)
334
+ child = CustomTensor._serialize_level(
335
+ container, child_level, depth + rank, copy
336
+ )
337
+ return {"level_desc": "sparse", "rank": rank, "level": child}
338
+ case _:
339
+ raise TypeError(f"unsupported level type {type(level).__name__}")
340
+
341
+
342
+ @dataclass
343
+ class DVECVector(BinsparseTensor):
344
+ values: Any = None
345
+ format: ClassVar[str] = "DVEC"
346
+
347
+ @classmethod
348
+ def _parse(cls, container, header, common, copy):
349
+ count = common["number_of_stored_values"]
350
+ return cls(**common, values=container.read_buffer("values", count, copy=copy))
351
+
352
+ def _serialize(self, container, copy):
353
+ container.write_buffer("values", np.asarray(self.values), copy=copy)
354
+ return {}
355
+
356
+
357
+ @dataclass
358
+ class DMATRMatrix(BinsparseTensor):
359
+ values: Any = None
360
+ format: ClassVar[str] = "DMATR"
361
+
362
+ @classmethod
363
+ def _parse(cls, container, header, common, copy):
364
+ count = common["number_of_stored_values"]
365
+ return cls(**common, values=container.read_buffer("values", count, copy=copy))
366
+
367
+ def _serialize(self, container, copy):
368
+ container.write_buffer("values", np.asarray(self.values), copy=copy)
369
+ return {}
370
+
371
+
372
+ @dataclass
373
+ class DMATCMatrix(BinsparseTensor):
374
+ values: Any = None
375
+ format: ClassVar[str] = "DMATC"
376
+
377
+ @classmethod
378
+ def _parse(cls, container, header, common, copy):
379
+ count = common["number_of_stored_values"]
380
+ return cls(**common, values=container.read_buffer("values", count, copy=copy))
381
+
382
+ def _serialize(self, container, copy):
383
+ container.write_buffer("values", np.asarray(self.values), copy=copy)
384
+ return {}
385
+
386
+
387
+ DMATMatrix = DMATRMatrix
388
+
389
+
390
+ @dataclass
391
+ class CVECVector(BinsparseTensor):
392
+ indices_0: Any = None
393
+ values: Any = None
394
+ format: ClassVar[str] = "CVEC"
395
+
396
+ @classmethod
397
+ def _parse(cls, container, header, common, copy):
398
+ count = common["number_of_stored_values"]
399
+ return cls(
400
+ **common,
401
+ indices_0=container.read_buffer("indices_0", copy=copy),
402
+ values=container.read_buffer("values", count, copy=copy),
403
+ )
404
+
405
+ def _serialize(self, container, copy):
406
+ container.write_buffer("indices_0", np.asarray(self.indices_0), copy=copy)
407
+ container.write_buffer("values", np.asarray(self.values), copy=copy)
408
+ return {}
409
+
410
+
411
+ @dataclass
412
+ class CSRMatrix(BinsparseTensor):
413
+ pointers_to_1: Any = None
414
+ indices_1: Any = None
415
+ values: Any = None
416
+ format: ClassVar[str] = "CSR"
417
+
418
+ @classmethod
419
+ def _parse(cls, container, header, common, copy):
420
+ count = common["number_of_stored_values"]
421
+ return cls(
422
+ **common,
423
+ pointers_to_1=container.read_buffer("pointers_to_1", copy=copy),
424
+ indices_1=container.read_buffer("indices_1", copy=copy),
425
+ values=container.read_buffer("values", count, copy=copy),
426
+ )
427
+
428
+ def _serialize(self, container, copy):
429
+ container.write_buffer(
430
+ "pointers_to_1", np.asarray(self.pointers_to_1), copy=copy
431
+ )
432
+ container.write_buffer("indices_1", np.asarray(self.indices_1), copy=copy)
433
+ container.write_buffer("values", np.asarray(self.values), copy=copy)
434
+ return {}
435
+
436
+
437
+ @dataclass
438
+ class CSCMatrix(CSRMatrix):
439
+ format: ClassVar[str] = "CSC"
440
+
441
+
442
+ @dataclass
443
+ class DCSRMatrix(BinsparseTensor):
444
+ indices_0: Any = None
445
+ pointers_to_1: Any = None
446
+ indices_1: Any = None
447
+ values: Any = None
448
+ format: ClassVar[str] = "DCSR"
449
+
450
+ @classmethod
451
+ def _parse(cls, container, header, common, copy):
452
+ count = common["number_of_stored_values"]
453
+ indices_0 = container.read_buffer("indices_0", copy=copy)
454
+ return cls(
455
+ **common,
456
+ indices_0=indices_0,
457
+ pointers_to_1=container.read_buffer("pointers_to_1", copy=copy),
458
+ indices_1=container.read_buffer("indices_1", copy=copy),
459
+ values=container.read_buffer("values", count, copy=copy),
460
+ )
461
+
462
+ def _serialize(self, container, copy):
463
+ container.write_buffer("indices_0", np.asarray(self.indices_0), copy=copy)
464
+ container.write_buffer(
465
+ "pointers_to_1", np.asarray(self.pointers_to_1), copy=copy
466
+ )
467
+ container.write_buffer("indices_1", np.asarray(self.indices_1), copy=copy)
468
+ container.write_buffer("values", np.asarray(self.values), copy=copy)
469
+ return {}
470
+
471
+
472
+ @dataclass
473
+ class DCSCMatrix(DCSRMatrix):
474
+ format: ClassVar[str] = "DCSC"
475
+
476
+
477
+ @dataclass
478
+ class COORMatrix(BinsparseTensor):
479
+ indices_0: Any = None
480
+ indices_1: Any = None
481
+ values: Any = None
482
+ format: ClassVar[str] = "COOR"
483
+
484
+ @classmethod
485
+ def _parse(cls, container, header, common, copy):
486
+ count = common["number_of_stored_values"]
487
+ return cls(
488
+ **common,
489
+ indices_0=container.read_buffer("indices_0", copy=copy),
490
+ indices_1=container.read_buffer("indices_1", copy=copy),
491
+ values=container.read_buffer("values", count, copy=copy),
492
+ )
493
+
494
+ def _serialize(self, container, copy):
495
+ container.write_buffer("indices_0", np.asarray(self.indices_0), copy=copy)
496
+ container.write_buffer("indices_1", np.asarray(self.indices_1), copy=copy)
497
+ container.write_buffer("values", np.asarray(self.values), copy=copy)
498
+ return {}
499
+
500
+
501
+ @dataclass
502
+ class COOCMatrix(COORMatrix):
503
+ format: ClassVar[str] = "COOC"
504
+
505
+
506
+ COOMatrix = COORMatrix
507
+
508
+
509
+ _FORMAT_CLASSES: dict[str, type[BinsparseTensor]] = {
510
+ "custom": CustomTensor,
511
+ "DVEC": DVECVector,
512
+ "DMAT": DMATRMatrix,
513
+ "DMATR": DMATRMatrix,
514
+ "DMATC": DMATCMatrix,
515
+ "CVEC": CVECVector,
516
+ "CSR": CSRMatrix,
517
+ "CSC": CSCMatrix,
518
+ "DCSR": DCSRMatrix,
519
+ "DCSC": DCSCMatrix,
520
+ "COO": COORMatrix,
521
+ "COOR": COORMatrix,
522
+ "COOC": COOCMatrix,
523
+ }
524
+
525
+
526
+ _ELEMENT = {"level_desc": "element"}
527
+
528
+
529
+ def _dense(level: dict[str, Any], rank: int = 1) -> dict[str, Any]:
530
+ return {"level_desc": "dense", "rank": rank, "level": level}
531
+
532
+
533
+ def _sparse(level: dict[str, Any], rank: int = 1) -> dict[str, Any]:
534
+ return {"level_desc": "sparse", "rank": rank, "level": level}
535
+
536
+
537
+ _PREDEFINED_LEVELS: dict[str, tuple[dict[str, Any], tuple[int, ...] | None]] = {
538
+ "DVEC": (_dense(_ELEMENT), None),
539
+ "DMATR": (_dense(_dense(_ELEMENT)), None),
540
+ "DMAT": (_dense(_dense(_ELEMENT)), None),
541
+ "DMATC": (_dense(_dense(_ELEMENT)), (1, 0)),
542
+ "CVEC": (_sparse(_ELEMENT), None),
543
+ "CSR": (_dense(_sparse(_ELEMENT)), None),
544
+ "CSC": (_dense(_sparse(_ELEMENT)), (1, 0)),
545
+ "DCSR": (_sparse(_sparse(_ELEMENT)), None),
546
+ "DCSC": (_sparse(_sparse(_ELEMENT)), (1, 0)),
547
+ "COOR": (_sparse(_ELEMENT, 2), None),
548
+ "COO": (_sparse(_ELEMENT, 2), None),
549
+ "COOC": (_sparse(_ELEMENT, 2), (1, 0)),
550
+ }
551
+
552
+
553
+ def _custom_alias(header: dict[str, Any]) -> str | None:
554
+ try:
555
+ custom = header["custom"]
556
+ descriptor = custom["level"]
557
+ transpose = custom.get("transpose")
558
+ except (KeyError, TypeError) as error:
559
+ raise BinsparseParseError("custom format requires custom.level") from error
560
+ transpose_tuple = None if transpose is None else tuple(transpose)
561
+ return next(
562
+ (
563
+ alias
564
+ for alias, (alias_descriptor, alias_transpose) in _PREDEFINED_LEVELS.items()
565
+ if descriptor == alias_descriptor and transpose_tuple == alias_transpose
566
+ ),
567
+ None,
568
+ )
569
+
570
+
571
+ __all__ = [
572
+ "BinsparseLevel", "IndexableLevel", "ElementLevel",
573
+ "DenseLevel", "SparseLevel", "BinsparseTensor", "CustomTensor",
574
+ "DVECVector", "DMATRMatrix", "DMATCMatrix", "DMATMatrix", "CVECVector",
575
+ "CSRMatrix", "CSCMatrix", "DCSRMatrix", "DCSCMatrix", "COORMatrix",
576
+ "COOCMatrix", "COOMatrix",
577
+ ]
binsparse/version.py ADDED
@@ -0,0 +1,29 @@
1
+ from __future__ import annotations
2
+
3
+ from semver import Version
4
+
5
+ from .errors import BinsparseParseError
6
+
7
+ BINSPARSE_VERSION = "0.1.0"
8
+ _SUPPORTED_VERSION = Version.parse(BINSPARSE_VERSION)
9
+
10
+
11
+ def check_binsparse_version(version: object) -> None:
12
+ """Raise if *version* is not a SemVer-compatible Binsparse version."""
13
+ parsed = parse_binsparse_version(version)
14
+ if not _SUPPORTED_VERSION.is_compatible(parsed):
15
+ raise BinsparseParseError(
16
+ f"unsupported Binsparse version {version!r}; "
17
+ f"expected a SemVer-compatible version with {BINSPARSE_VERSION!r}"
18
+ )
19
+
20
+
21
+ def parse_binsparse_version(version: object) -> Version:
22
+ if not isinstance(version, str):
23
+ raise BinsparseParseError("Binsparse version must be a string")
24
+ try:
25
+ return Version.parse(version)
26
+ except ValueError as error:
27
+ raise BinsparseParseError(
28
+ f"invalid Binsparse SemVer version {version!r}"
29
+ ) from error
@@ -0,0 +1,18 @@
1
+ Metadata-Version: 2.5
2
+ Name: binsparse
3
+ Version: 0.1.0
4
+ Author-email: Willow Ahrens <ahrens@gatech.edu>
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: h5py<4,>=3.16.0
7
+ Requires-Dist: numpy<3,>=2
8
+ Requires-Dist: semver<4,>=3
9
+ Provides-Extra: conversions
10
+ Requires-Dist: scipy; extra == 'conversions'
11
+ Requires-Dist: sparse; extra == 'conversions'
12
+ Requires-Dist: torch; extra == 'conversions'
13
+ Provides-Extra: scipy
14
+ Requires-Dist: scipy; extra == 'scipy'
15
+ Provides-Extra: sparse
16
+ Requires-Dist: sparse; extra == 'sparse'
17
+ Provides-Extra: torch
18
+ Requires-Dist: torch; extra == 'torch'
@@ -0,0 +1,18 @@
1
+ binsparse/__init__.py,sha256=5u8dntzUBcs_n_j_1MEi9QS7O5cmwmjYNOwUdOg7Iqk,1373
2
+ binsparse/container.py,sha256=OKX96l7oPLB-B47MS5t-ExMq7_0r7PGSCePqjkMjZKY,12473
3
+ binsparse/errors.py,sha256=2m5yLYLAl7aKrSBHD5GAhE54oVkpWEb7C9wZ8VOO5YY,171
4
+ binsparse/io.py,sha256=wCSEnMVXXaL880Lf9zyMXjpdKSkiX6vEERM00c0uEuQ,4252
5
+ binsparse/tensor.py,sha256=2Sg-oP1vqpaWK_Cw92kis242GwMAfTCrMCKAxEHqYtk,20060
6
+ binsparse/version.py,sha256=wWzDlzR0NAxmjMBcuUiB6iCt95Xj919IXtEmnkd-WSU,963
7
+ binsparse/conversions/__init__.py,sha256=Dny-FQagLMBsD-x6Nj6ePEUtbTA1mqXfsKVqEyLCBfY,400
8
+ binsparse/conversions/numpy.py,sha256=LqwaFE77T1UC-TRTPbSykFvCP0NxuMEB3f_odyLVoHY,2010
9
+ binsparse/conversions/scipy.py,sha256=TBVdRvt-55G24rAW9Y8JS3SGSA-iV9y33C0bq1Y5OK8,3344
10
+ binsparse/conversions/sparse.py,sha256=ogRQD1MjC_iWfgmvhdLpXH94heGgW6rBlZcPztuMS1Q,2831
11
+ binsparse/conversions/torch.py,sha256=BWJWGkrnNLii11FctCE8xAbMSCqA02x50rFVEl6bqJY,5916
12
+ reference_cli/__init__.py,sha256=g9DI-PGXVrJ8CakgxLUg9dEWzW4LbEl2K8Mc26dCDx4,72
13
+ reference_cli/converters.py,sha256=8EWMwwgdrg3B66QgOAI8CAztnot6thCdFDCF6PuUh6w,5802
14
+ reference_cli/framework.py,sha256=5mXnsI0aWNYqfKIOyEJc07BjstJvXj-QGjCiGGy2eKg,2585
15
+ reference_cli/reformat.py,sha256=JmRVvk49CwiScmwKRDH_2K7ix4hamB_xoOYt2puv0k0,10551
16
+ binsparse-0.1.0.dist-info/METADATA,sha256=zc7iTfZEa4IvEna9MYQ4knCSwk_zHh9hFoDxuss3bG0,561
17
+ binsparse-0.1.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
18
+ binsparse-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1 @@
1
+ """Reference converter executables for Binsparse compliance testing."""