bw-processing 1.4__tar.gz → 1.5__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.
- {bw_processing-1.4/src/bw_processing.egg-info → bw_processing-1.5}/PKG-INFO +1 -1
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/__init__.py +1 -1
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/datapackage.py +91 -99
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/matrix_entry.py +10 -8
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/utils.py +5 -1
- {bw_processing-1.4 → bw_processing-1.5/src/bw_processing.egg-info}/PKG-INFO +1 -1
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_datapackage.py +111 -51
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_matrix_entry.py +103 -0
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_utils.py +15 -3
- {bw_processing-1.4 → bw_processing-1.5}/LICENSE +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/MANIFEST.in +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/README.md +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/pyproject.toml +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/setup.cfg +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/array_creation.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/constants.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/errors.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/examples/__init__.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/examples/datapackage_1/another name.indices.parquet +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/examples/datapackage_1/sa-data-vector-from-dict.data.parquet +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/examples/datapackage_1/sa-data-vector-from-dict.distributions.parquet +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/examples/datapackage_1/sa-data-vector-from-dict.flip.parquet +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/examples/datapackage_1/sa-data-vector-from-dict.indices.parquet +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/examples/datapackage_1/some name.data.parquet +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/examples/datapackage_1/some name.flip.parquet +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/examples/datapackage_1/some name.indices.parquet +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/examples/datapackage_2.zip +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/examples/interfaces.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/examples/parquet_files.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/examples/simple.zip +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/filesystem.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/indexing.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/io_helpers.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/io_parquet_helpers.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/io_pyarrow_helpers.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/merging.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/param_labels.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/proxies.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing/unique_fields.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing.egg-info/SOURCES.txt +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing.egg-info/dependency_links.txt +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing.egg-info/requires.txt +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/src/bw_processing.egg-info/top_level.txt +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_array_creation.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_filesystem.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_filtered_datapackage.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_indexing.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_integration.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_interfaces.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_io_parquet_helpers.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_io_pyarrow_helpers.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_loading.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_merging.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_params.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_proxies.py +0 -0
- {bw_processing-1.4 → bw_processing-1.5}/tests/test_unique_fields.py +0 -0
|
@@ -500,7 +500,6 @@ class Datapackage(DatapackageBase):
|
|
|
500
500
|
dict_iterator: Any = None,
|
|
501
501
|
nrows: Optional[int] = None,
|
|
502
502
|
matrix_serialize_format_type: Optional[MatrixSerializeFormat] = None,
|
|
503
|
-
scale_array: Optional[np.ndarray] = None,
|
|
504
503
|
**kwargs,
|
|
505
504
|
) -> None:
|
|
506
505
|
"""Create a persistant vector from an iterator. Uses the utility function ``resolve_dict_iterator``.
|
|
@@ -512,6 +511,7 @@ class Datapackage(DatapackageBase):
|
|
|
512
511
|
indices_array,
|
|
513
512
|
distributions_array,
|
|
514
513
|
flip_array,
|
|
514
|
+
rescale_array,
|
|
515
515
|
) = resolve_dict_iterator(dict_iterator, nrows)
|
|
516
516
|
self.add_persistent_vector(
|
|
517
517
|
matrix=matrix,
|
|
@@ -521,7 +521,7 @@ class Datapackage(DatapackageBase):
|
|
|
521
521
|
indices_array=indices_array,
|
|
522
522
|
flip_array=flip_array,
|
|
523
523
|
distributions_array=distributions_array,
|
|
524
|
-
|
|
524
|
+
rescale_array=rescale_array,
|
|
525
525
|
matrix_serialize_format_type=matrix_serialize_format_type,
|
|
526
526
|
**kwargs,
|
|
527
527
|
)
|
|
@@ -536,35 +536,19 @@ class Datapackage(DatapackageBase):
|
|
|
536
536
|
"""Add matrix data from a list of :class:`MatrixEntry` objects.
|
|
537
537
|
|
|
538
538
|
High-level convenience method that does not require working directly
|
|
539
|
-
with NumPy arrays.
|
|
540
|
-
|
|
541
|
-
If any entry has a ``rescale`` value other than ``1.0``, all rescale
|
|
542
|
-
values are collected into a ``scale_array`` resource. The entries are
|
|
543
|
-
pre-sorted by ``(row, col, amount, uncertainty_type)`` — matching
|
|
544
|
-
the internal sort applied by :func:`resolve_dict_iterator` — so the
|
|
545
|
-
scale values stay aligned with the stored indices and data arrays.
|
|
539
|
+
with NumPy arrays. If any entry has a ``rescale`` value other than
|
|
540
|
+
``1.0``, the rescale values are stored as a ``rescale_array`` resource.
|
|
546
541
|
|
|
547
542
|
Args:
|
|
548
543
|
matrix: Name of the target matrix (e.g. ``"technosphere"``).
|
|
549
544
|
entries: List of :class:`.MatrixEntry` instances.
|
|
550
545
|
name: Optional resource group name; auto-generated if omitted.
|
|
551
546
|
"""
|
|
552
|
-
has_rescale = any(e.rescale != 1.0 for e in entries)
|
|
553
|
-
if has_rescale:
|
|
554
|
-
entries = sorted(
|
|
555
|
-
entries,
|
|
556
|
-
key=lambda e: (e.row, e.col, float(np.float32(e.amount)), e.uncertainty_type),
|
|
557
|
-
)
|
|
558
|
-
scale_array = np.array([e.rescale for e in entries], dtype=np.float32)
|
|
559
|
-
else:
|
|
560
|
-
scale_array = None
|
|
561
|
-
|
|
562
547
|
self.add_persistent_vector_from_iterator(
|
|
563
548
|
matrix=matrix,
|
|
564
549
|
name=name,
|
|
565
550
|
dict_iterator=(e.as_dict() for e in entries),
|
|
566
551
|
nrows=len(entries),
|
|
567
|
-
scale_array=scale_array,
|
|
568
552
|
)
|
|
569
553
|
|
|
570
554
|
def add_array_entries(
|
|
@@ -576,8 +560,8 @@ class Datapackage(DatapackageBase):
|
|
|
576
560
|
"""Add matrix data from a list of :class:`.ArrayEntry` objects.
|
|
577
561
|
|
|
578
562
|
Each :class:`.ArrayEntry` becomes one persistent-array resource group.
|
|
579
|
-
Resource group names are auto-generated. If an entry has a ``
|
|
580
|
-
array it is stored as a ``
|
|
563
|
+
Resource group names are auto-generated. If an entry has a ``rescale``
|
|
564
|
+
array it is stored as a ``rescale_array`` resource (``kind="rescale"``).
|
|
581
565
|
|
|
582
566
|
Args:
|
|
583
567
|
matrix: Name of the target matrix (e.g. ``"technosphere"``).
|
|
@@ -592,7 +576,7 @@ class Datapackage(DatapackageBase):
|
|
|
592
576
|
indices_array=indices,
|
|
593
577
|
data_array=entry.data,
|
|
594
578
|
flip_array=entry.flip,
|
|
595
|
-
|
|
579
|
+
rescale_array=entry.rescale,
|
|
596
580
|
)
|
|
597
581
|
|
|
598
582
|
def add_persistent_vector(
|
|
@@ -604,7 +588,7 @@ class Datapackage(DatapackageBase):
|
|
|
604
588
|
data_array: Optional[np.ndarray] = None,
|
|
605
589
|
flip_array: Optional[np.ndarray] = None,
|
|
606
590
|
distributions_array: Optional[np.ndarray] = None,
|
|
607
|
-
|
|
591
|
+
rescale_array: Optional[np.ndarray] = None,
|
|
608
592
|
params_array: Optional[np.ndarray] = None,
|
|
609
593
|
param_labels: Optional[list] = None,
|
|
610
594
|
param_label_schema: Optional[AnyLabelSchema] = None,
|
|
@@ -614,7 +598,7 @@ class Datapackage(DatapackageBase):
|
|
|
614
598
|
) -> None:
|
|
615
599
|
"""Add a persistent vector resource group to the datapackage.
|
|
616
600
|
|
|
617
|
-
``
|
|
601
|
+
``rescale_array`` is an optional 1-D float array of the same length as
|
|
618
602
|
``indices_array``. Each element is a multiplicative factor applied to
|
|
619
603
|
the corresponding data value — whether static or stochastic — before
|
|
620
604
|
the value is inserted into the matrix. Typical uses are allocation
|
|
@@ -697,18 +681,18 @@ class Datapackage(DatapackageBase):
|
|
|
697
681
|
)
|
|
698
682
|
if flip_array is not None:
|
|
699
683
|
flip_array = load_bytes(flip_array)
|
|
684
|
+
if flip_array.dtype != bool:
|
|
685
|
+
raise WrongDatatype(
|
|
686
|
+
"`flip_array` dtype is {}, but must be `bool`".format(flip_array.dtype)
|
|
687
|
+
)
|
|
688
|
+
if flip_array.shape != indices_array.shape:
|
|
689
|
+
raise ShapeMismatch(
|
|
690
|
+
"`flip_array` shape ({}) doesn't match `indices_array` ({}).".format(
|
|
691
|
+
flip_array.shape, indices_array.shape
|
|
692
|
+
)
|
|
693
|
+
)
|
|
700
694
|
# If no flips, don't need to store it
|
|
701
695
|
if flip_array.sum():
|
|
702
|
-
if flip_array.dtype != bool:
|
|
703
|
-
raise WrongDatatype(
|
|
704
|
-
"`flip_array` dtype is {}, but must be `bool`".format(flip_array.dtype)
|
|
705
|
-
)
|
|
706
|
-
elif flip_array.shape != indices_array.shape:
|
|
707
|
-
raise ShapeMismatch(
|
|
708
|
-
"`flip_array` shape ({}) doesn't match `indices_array` ({}).".format(
|
|
709
|
-
flip_array.shape, indices_array.shape
|
|
710
|
-
)
|
|
711
|
-
)
|
|
712
696
|
self._add_numpy_array_resource(
|
|
713
697
|
array=flip_array,
|
|
714
698
|
group=name,
|
|
@@ -720,9 +704,9 @@ class Datapackage(DatapackageBase):
|
|
|
720
704
|
meta_type="generic",
|
|
721
705
|
**kwargs,
|
|
722
706
|
)
|
|
723
|
-
if
|
|
724
|
-
self.
|
|
725
|
-
|
|
707
|
+
if rescale_array is not None:
|
|
708
|
+
self._add_rescale_array_resource(
|
|
709
|
+
rescale_array=rescale_array,
|
|
726
710
|
indices_array=indices_array,
|
|
727
711
|
name=name,
|
|
728
712
|
keep_proxy=keep_proxy,
|
|
@@ -766,7 +750,7 @@ class Datapackage(DatapackageBase):
|
|
|
766
750
|
indices_array: np.ndarray,
|
|
767
751
|
name: Optional[str] = None,
|
|
768
752
|
flip_array: Optional[np.ndarray] = None,
|
|
769
|
-
|
|
753
|
+
rescale_array: Optional[np.ndarray] = None,
|
|
770
754
|
params_array: Optional[np.ndarray] = None,
|
|
771
755
|
param_labels: Optional[list] = None,
|
|
772
756
|
param_label_schema: Optional[AnyLabelSchema] = None,
|
|
@@ -776,7 +760,7 @@ class Datapackage(DatapackageBase):
|
|
|
776
760
|
) -> None:
|
|
777
761
|
"""Add a persistent array resource group to the datapackage.
|
|
778
762
|
|
|
779
|
-
``
|
|
763
|
+
``rescale_array`` is an optional 1-D float array of the same length as
|
|
780
764
|
``indices_array``. Each element is a multiplicative factor applied to
|
|
781
765
|
the corresponding data value — whether static or stochastic — before
|
|
782
766
|
the value is inserted into the matrix. Typical uses are allocation
|
|
@@ -834,17 +818,18 @@ class Datapackage(DatapackageBase):
|
|
|
834
818
|
)
|
|
835
819
|
if flip_array is not None:
|
|
836
820
|
flip_array = load_bytes(flip_array)
|
|
837
|
-
if flip_array.
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
flip_array.shape, indices_array.shape
|
|
846
|
-
)
|
|
821
|
+
if flip_array.dtype != bool:
|
|
822
|
+
raise WrongDatatype(
|
|
823
|
+
"`flip_array` dtype is {}, but must be `bool`".format(flip_array.dtype)
|
|
824
|
+
)
|
|
825
|
+
if flip_array.shape != indices_array.shape:
|
|
826
|
+
raise ShapeMismatch(
|
|
827
|
+
"`flip_array` shape ({}) doesn't match `indices_array` ({}).".format(
|
|
828
|
+
flip_array.shape, indices_array.shape
|
|
847
829
|
)
|
|
830
|
+
)
|
|
831
|
+
# If no flips, don't need to store it
|
|
832
|
+
if flip_array.sum():
|
|
848
833
|
self._add_numpy_array_resource(
|
|
849
834
|
array=flip_array,
|
|
850
835
|
group=name,
|
|
@@ -856,9 +841,9 @@ class Datapackage(DatapackageBase):
|
|
|
856
841
|
meta_type="generic",
|
|
857
842
|
**kwargs,
|
|
858
843
|
)
|
|
859
|
-
if
|
|
860
|
-
self.
|
|
861
|
-
|
|
844
|
+
if rescale_array is not None:
|
|
845
|
+
self._add_rescale_array_resource(
|
|
846
|
+
rescale_array=rescale_array,
|
|
862
847
|
indices_array=indices_array,
|
|
863
848
|
name=name,
|
|
864
849
|
keep_proxy=keep_proxy,
|
|
@@ -927,7 +912,7 @@ class Datapackage(DatapackageBase):
|
|
|
927
912
|
if kind == "indices":
|
|
928
913
|
meta_object = "vector"
|
|
929
914
|
meta_type = "indices"
|
|
930
|
-
elif kind in ("flip", "
|
|
915
|
+
elif kind in ("flip", "rescale", "params"):
|
|
931
916
|
meta_object = "vector"
|
|
932
917
|
meta_type = "generic"
|
|
933
918
|
elif kind == "distributions":
|
|
@@ -968,32 +953,32 @@ class Datapackage(DatapackageBase):
|
|
|
968
953
|
|
|
969
954
|
self._modified = set()
|
|
970
955
|
|
|
971
|
-
def
|
|
956
|
+
def _add_rescale_array_resource(
|
|
972
957
|
self,
|
|
973
958
|
*,
|
|
974
|
-
|
|
959
|
+
rescale_array: np.ndarray,
|
|
975
960
|
indices_array: np.ndarray,
|
|
976
961
|
name: str,
|
|
977
962
|
keep_proxy: bool,
|
|
978
963
|
matrix_serialize_format_type: Optional[MatrixSerializeFormat],
|
|
979
964
|
**kwargs,
|
|
980
965
|
) -> None:
|
|
981
|
-
|
|
982
|
-
if not np.issubdtype(
|
|
966
|
+
rescale_array = load_bytes(rescale_array)
|
|
967
|
+
if not np.issubdtype(rescale_array.dtype, np.floating):
|
|
983
968
|
raise WrongDatatype(
|
|
984
|
-
"`
|
|
969
|
+
"`rescale_array` dtype is {}, but must be a float dtype".format(rescale_array.dtype)
|
|
985
970
|
)
|
|
986
|
-
elif
|
|
971
|
+
elif rescale_array.shape != indices_array.shape:
|
|
987
972
|
raise ShapeMismatch(
|
|
988
|
-
"`
|
|
989
|
-
|
|
973
|
+
"`rescale_array` shape ({}) doesn't match `indices_array` ({}).".format(
|
|
974
|
+
rescale_array.shape, indices_array.shape
|
|
990
975
|
)
|
|
991
976
|
)
|
|
992
977
|
self._add_numpy_array_resource(
|
|
993
|
-
array=
|
|
978
|
+
array=rescale_array,
|
|
994
979
|
group=name,
|
|
995
|
-
name=name + ".
|
|
996
|
-
kind="
|
|
980
|
+
name=name + ".rescale",
|
|
981
|
+
kind="rescale",
|
|
997
982
|
keep_proxy=keep_proxy,
|
|
998
983
|
matrix_serialize_format_type=matrix_serialize_format_type,
|
|
999
984
|
meta_object="vector",
|
|
@@ -1147,7 +1132,7 @@ class Datapackage(DatapackageBase):
|
|
|
1147
1132
|
indices_array: np.ndarray, # Not interface
|
|
1148
1133
|
name: Optional[str] = None,
|
|
1149
1134
|
flip_array: Optional[np.ndarray] = None, # Not interface
|
|
1150
|
-
|
|
1135
|
+
rescale_array: Optional[np.ndarray] = None, # Not interface
|
|
1151
1136
|
params_array: Optional[np.ndarray] = None, # Not interface
|
|
1152
1137
|
param_labels: Optional[list] = None,
|
|
1153
1138
|
param_label_schema: Optional[AnyLabelSchema] = None,
|
|
@@ -1161,7 +1146,7 @@ class Datapackage(DatapackageBase):
|
|
|
1161
1146
|
stored on disk. ``interface`` must implement ``__next__()`` and return a
|
|
1162
1147
|
1-D numpy array of length ``len(indices_array)`` each time it is called.
|
|
1163
1148
|
|
|
1164
|
-
The ``indices_array``, optional ``flip_array``, optional ``
|
|
1149
|
+
The ``indices_array``, optional ``flip_array``, optional ``rescale_array``,
|
|
1165
1150
|
and optional ``params_array`` are static and are stored as normal numpy
|
|
1166
1151
|
resources. See ``add_persistent_vector`` for documentation of the
|
|
1167
1152
|
``params_array``, ``param_labels``, and ``param_label_schema`` arguments.
|
|
@@ -1175,7 +1160,7 @@ class Datapackage(DatapackageBase):
|
|
|
1175
1160
|
name: Optional resource group name; auto-generated if omitted.
|
|
1176
1161
|
flip_array: Optional boolean array; where ``True`` the value is
|
|
1177
1162
|
multiplied by ``-1`` before insertion.
|
|
1178
|
-
|
|
1163
|
+
rescale_array: Optional 1-D float array of multiplicative factors
|
|
1179
1164
|
applied before matrix insertion.
|
|
1180
1165
|
keep_proxy: If ``True``, store a proxy rather than the raw array
|
|
1181
1166
|
for on-disk resources.
|
|
@@ -1202,17 +1187,18 @@ class Datapackage(DatapackageBase):
|
|
|
1202
1187
|
)
|
|
1203
1188
|
if flip_array is not None:
|
|
1204
1189
|
flip_array = load_bytes(flip_array)
|
|
1205
|
-
if flip_array.
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
flip_array.shape, indices_array.shape
|
|
1214
|
-
)
|
|
1190
|
+
if flip_array.dtype != bool:
|
|
1191
|
+
raise WrongDatatype(
|
|
1192
|
+
"`flip_array` dtype is {}, but must be `bool`".format(flip_array.dtype)
|
|
1193
|
+
)
|
|
1194
|
+
if flip_array.shape != indices_array.shape:
|
|
1195
|
+
raise ShapeMismatch(
|
|
1196
|
+
"`flip_array` shape ({}) doesn't match `indices_array` ({}).".format(
|
|
1197
|
+
flip_array.shape, indices_array.shape
|
|
1215
1198
|
)
|
|
1199
|
+
)
|
|
1200
|
+
# If no flips, don't need to store it
|
|
1201
|
+
if flip_array.sum():
|
|
1216
1202
|
self._add_numpy_array_resource(
|
|
1217
1203
|
array=flip_array,
|
|
1218
1204
|
group=name,
|
|
@@ -1224,9 +1210,9 @@ class Datapackage(DatapackageBase):
|
|
|
1224
1210
|
meta_type="generic",
|
|
1225
1211
|
**kwargs,
|
|
1226
1212
|
)
|
|
1227
|
-
if
|
|
1228
|
-
self.
|
|
1229
|
-
|
|
1213
|
+
if rescale_array is not None:
|
|
1214
|
+
self._add_rescale_array_resource(
|
|
1215
|
+
rescale_array=rescale_array,
|
|
1230
1216
|
indices_array=indices_array,
|
|
1231
1217
|
name=name,
|
|
1232
1218
|
keep_proxy=keep_proxy,
|
|
@@ -1280,7 +1266,7 @@ class Datapackage(DatapackageBase):
|
|
|
1280
1266
|
indices_array: np.ndarray, # Not interface
|
|
1281
1267
|
name: Optional[str] = None,
|
|
1282
1268
|
flip_array: Optional[np.ndarray] = None,
|
|
1283
|
-
|
|
1269
|
+
rescale_array: Optional[np.ndarray] = None, # Not interface
|
|
1284
1270
|
params_array: Optional[np.ndarray] = None, # Not interface
|
|
1285
1271
|
param_labels: Optional[list] = None,
|
|
1286
1272
|
param_label_schema: Optional[AnyLabelSchema] = None,
|
|
@@ -1296,7 +1282,7 @@ class Datapackage(DatapackageBase):
|
|
|
1296
1282
|
array for ``args[1]``. ``ncols`` may be ``None`` for an infinite
|
|
1297
1283
|
interface.
|
|
1298
1284
|
|
|
1299
|
-
The ``indices_array``, optional ``flip_array``, optional ``
|
|
1285
|
+
The ``indices_array``, optional ``flip_array``, optional ``rescale_array``,
|
|
1300
1286
|
and optional ``params_array`` are static and are stored as normal numpy
|
|
1301
1287
|
resources. For dynamic arrays the column count of ``params_array`` is
|
|
1302
1288
|
not validated against the interface (whose column count may be unknown at
|
|
@@ -1312,7 +1298,7 @@ class Datapackage(DatapackageBase):
|
|
|
1312
1298
|
name: Optional resource group name; auto-generated if omitted.
|
|
1313
1299
|
flip_array: Optional boolean array; where ``True`` the value is
|
|
1314
1300
|
multiplied by ``-1`` before insertion.
|
|
1315
|
-
|
|
1301
|
+
rescale_array: Optional 1-D float array of multiplicative factors
|
|
1316
1302
|
applied before matrix insertion.
|
|
1317
1303
|
keep_proxy: If ``True``, store a proxy rather than the raw array
|
|
1318
1304
|
for on-disk resources.
|
|
@@ -1322,8 +1308,13 @@ class Datapackage(DatapackageBase):
|
|
|
1322
1308
|
self._check_params_args(params_array, param_labels, param_label_schema)
|
|
1323
1309
|
self._prepare_modifications()
|
|
1324
1310
|
|
|
1325
|
-
if isinstance(flip_array, np.ndarray)
|
|
1326
|
-
flip_array
|
|
1311
|
+
if isinstance(flip_array, np.ndarray):
|
|
1312
|
+
if flip_array.dtype != bool:
|
|
1313
|
+
raise WrongDatatype(
|
|
1314
|
+
"`flip_array` dtype is {}, but must be `bool`".format(flip_array.dtype)
|
|
1315
|
+
)
|
|
1316
|
+
if not flip_array.sum():
|
|
1317
|
+
flip_array = None
|
|
1327
1318
|
|
|
1328
1319
|
kwargs.update({"matrix": matrix, "category": "array", "nrows": len(indices_array)})
|
|
1329
1320
|
name = self._prepare_name(name)
|
|
@@ -1342,17 +1333,18 @@ class Datapackage(DatapackageBase):
|
|
|
1342
1333
|
)
|
|
1343
1334
|
if flip_array is not None:
|
|
1344
1335
|
flip_array = load_bytes(flip_array)
|
|
1345
|
-
if flip_array.
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
flip_array.shape, indices_array.shape
|
|
1354
|
-
)
|
|
1336
|
+
if flip_array.dtype != bool:
|
|
1337
|
+
raise WrongDatatype(
|
|
1338
|
+
"`flip_array` dtype is {}, but must be `bool`".format(flip_array.dtype)
|
|
1339
|
+
)
|
|
1340
|
+
if flip_array.shape != indices_array.shape:
|
|
1341
|
+
raise ShapeMismatch(
|
|
1342
|
+
"`flip_array` shape ({}) doesn't match `indices_array` ({}).".format(
|
|
1343
|
+
flip_array.shape, indices_array.shape
|
|
1355
1344
|
)
|
|
1345
|
+
)
|
|
1346
|
+
# If no flips, don't need to store it
|
|
1347
|
+
if flip_array.sum():
|
|
1356
1348
|
self._add_numpy_array_resource(
|
|
1357
1349
|
array=flip_array,
|
|
1358
1350
|
group=name,
|
|
@@ -1364,9 +1356,9 @@ class Datapackage(DatapackageBase):
|
|
|
1364
1356
|
meta_type="generic",
|
|
1365
1357
|
**kwargs,
|
|
1366
1358
|
)
|
|
1367
|
-
if
|
|
1368
|
-
self.
|
|
1369
|
-
|
|
1359
|
+
if rescale_array is not None:
|
|
1360
|
+
self._add_rescale_array_resource(
|
|
1361
|
+
rescale_array=rescale_array,
|
|
1370
1362
|
indices_array=indices_array,
|
|
1371
1363
|
name=name,
|
|
1372
1364
|
keep_proxy=keep_proxy,
|
|
@@ -60,7 +60,9 @@ class MatrixEntry:
|
|
|
60
60
|
negative: Whether the underlying value is negative.
|
|
61
61
|
rescale: Per-exchange multiplicative factor applied before matrix
|
|
62
62
|
insertion. ``1.0`` (the default) leaves the value unchanged.
|
|
63
|
-
Stored as a ``
|
|
63
|
+
Stored as a ``rescale_array`` resource (``kind="rescale"``). Note
|
|
64
|
+
that the Python ``float`` value is downcast to ``numpy.float32``
|
|
65
|
+
when written to the structured array.
|
|
64
66
|
"""
|
|
65
67
|
|
|
66
68
|
row: int
|
|
@@ -104,16 +106,16 @@ class ArrayEntry:
|
|
|
104
106
|
cols: 1-D sequence of integer column indices, one per matrix entry.
|
|
105
107
|
data: 2-D array of shape ``(n_entries, n_scenarios)``.
|
|
106
108
|
flip: Optional 1-D boolean sequence of length ``n_entries``.
|
|
107
|
-
|
|
109
|
+
rescale: Optional 1-D float array of per-entry multiplicative factors
|
|
108
110
|
(one per row). ``1.0`` leaves the value unchanged. Stored as a
|
|
109
|
-
``
|
|
111
|
+
``rescale_array`` resource (``kind="rescale"``).
|
|
110
112
|
"""
|
|
111
113
|
|
|
112
114
|
rows: np.ndarray
|
|
113
115
|
cols: np.ndarray
|
|
114
116
|
data: np.ndarray
|
|
115
117
|
flip: Optional[np.ndarray] = None
|
|
116
|
-
|
|
118
|
+
rescale: Optional[np.ndarray] = None
|
|
117
119
|
|
|
118
120
|
def __post_init__(self):
|
|
119
121
|
self.rows = np.asarray(self.rows)
|
|
@@ -142,11 +144,11 @@ class ArrayEntry:
|
|
|
142
144
|
raise ValueError(
|
|
143
145
|
f"`flip` shape {self.flip.shape} doesn't match `rows` shape {self.rows.shape}"
|
|
144
146
|
)
|
|
145
|
-
if self.
|
|
146
|
-
self.
|
|
147
|
-
if self.
|
|
147
|
+
if self.rescale is not None:
|
|
148
|
+
self.rescale = np.asarray(self.rescale, dtype=np.float32)
|
|
149
|
+
if self.rescale.shape != self.rows.shape:
|
|
148
150
|
raise ValueError(
|
|
149
|
-
f"`
|
|
151
|
+
f"`rescale` shape {self.rescale.shape} doesn't match `rows` shape {self.rows.shape}"
|
|
150
152
|
)
|
|
151
153
|
|
|
152
154
|
|
|
@@ -64,6 +64,7 @@ def dictionary_formatter(row: dict) -> tuple:
|
|
|
64
64
|
row.get("maximum", np.nan),
|
|
65
65
|
row.get("negative", False),
|
|
66
66
|
row.get("flip", False),
|
|
67
|
+
row.get("rescale", 1.0),
|
|
67
68
|
)
|
|
68
69
|
|
|
69
70
|
|
|
@@ -73,11 +74,13 @@ def resolve_dict_iterator(iterator: Any, nrows: int = None) -> tuple:
|
|
|
73
74
|
data = (dictionary_formatter(row) for row in iterator)
|
|
74
75
|
array = create_structured_array(
|
|
75
76
|
data,
|
|
76
|
-
INDICES_DTYPE + [("amount", np.float32)] + UNCERTAINTY_DTYPE + [("flip", bool)],
|
|
77
|
+
INDICES_DTYPE + [("amount", np.float32)] + UNCERTAINTY_DTYPE + [("flip", bool), ("rescale", np.float32)],
|
|
77
78
|
nrows=nrows,
|
|
78
79
|
sort=True,
|
|
79
80
|
sort_fields=sort_fields,
|
|
80
81
|
)
|
|
82
|
+
rescale = array["rescale"]
|
|
83
|
+
rescale_array = rescale if (rescale != 1.0).any() else None
|
|
81
84
|
return (
|
|
82
85
|
array["amount"],
|
|
83
86
|
# Not repacking fields would cause this multi-field index to return a view
|
|
@@ -98,6 +101,7 @@ def resolve_dict_iterator(iterator: Any, nrows: int = None) -> tuple:
|
|
|
98
101
|
]
|
|
99
102
|
),
|
|
100
103
|
array["flip"],
|
|
104
|
+
rescale_array,
|
|
101
105
|
)
|
|
102
106
|
|
|
103
107
|
|
|
@@ -330,6 +330,23 @@ def test_add_persistent_vector_flip_dtype():
|
|
|
330
330
|
)
|
|
331
331
|
|
|
332
332
|
|
|
333
|
+
def test_add_persistent_vector_flip_dtype_all_zeros():
|
|
334
|
+
# A non-bool flip that is all-zeros must still raise WrongDatatype;
|
|
335
|
+
# previously the dtype check was skipped when sum() == 0.
|
|
336
|
+
dp = create_datapackage()
|
|
337
|
+
data_array = np.array([2, 7, 12])
|
|
338
|
+
flip_array = np.array([0, 0, 0]) # all falsy, but wrong dtype
|
|
339
|
+
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
340
|
+
with pytest.raises(WrongDatatype):
|
|
341
|
+
dp.add_persistent_vector(
|
|
342
|
+
matrix="sa_matrix",
|
|
343
|
+
data_array=data_array,
|
|
344
|
+
name="sa-data-vector",
|
|
345
|
+
flip_array=flip_array,
|
|
346
|
+
indices_array=indices_array,
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
|
|
333
350
|
def test_add_persistent_vector_flip_shapemistmatch():
|
|
334
351
|
dp = create_datapackage()
|
|
335
352
|
data_array = np.array([2, 7, 12])
|
|
@@ -386,6 +403,21 @@ def test_add_persistent_array_flip_dtype():
|
|
|
386
403
|
)
|
|
387
404
|
|
|
388
405
|
|
|
406
|
+
def test_add_persistent_array_flip_dtype_all_zeros():
|
|
407
|
+
dp = create_datapackage()
|
|
408
|
+
data_array = np.arange(12).reshape(3, 4)
|
|
409
|
+
flip_array = np.array([0, 0, 0]) # all falsy, but wrong dtype
|
|
410
|
+
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
411
|
+
with pytest.raises(WrongDatatype):
|
|
412
|
+
dp.add_persistent_array(
|
|
413
|
+
matrix="sa_matrix",
|
|
414
|
+
data_array=data_array,
|
|
415
|
+
name="sa-data-vector",
|
|
416
|
+
flip_array=flip_array,
|
|
417
|
+
indices_array=indices_array,
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
|
|
389
421
|
def test_add_persistent_array_flip_shapemistmatch():
|
|
390
422
|
dp = create_datapackage()
|
|
391
423
|
data_array = np.arange(12).reshape(3, 4)
|
|
@@ -415,6 +447,20 @@ def test_add_dynamic_array_flip_dtype():
|
|
|
415
447
|
)
|
|
416
448
|
|
|
417
449
|
|
|
450
|
+
def test_add_dynamic_array_flip_dtype_all_zeros():
|
|
451
|
+
dp = create_datapackage()
|
|
452
|
+
flip_array = np.array([0, 0, 0]) # all falsy, but wrong dtype
|
|
453
|
+
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
454
|
+
with pytest.raises(WrongDatatype):
|
|
455
|
+
dp.add_dynamic_array(
|
|
456
|
+
matrix="sa_matrix",
|
|
457
|
+
interface=Dummy(),
|
|
458
|
+
name="sa-data-vector",
|
|
459
|
+
flip_array=flip_array,
|
|
460
|
+
indices_array=indices_array,
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
|
|
418
464
|
def test_add_dynamic_array_flip_shapemistmatch():
|
|
419
465
|
dp = create_datapackage()
|
|
420
466
|
flip_array = np.array([0, 1, 0, 1], dtype=bool)
|
|
@@ -443,6 +489,20 @@ def test_add_dynamic_vector_flip_dtype():
|
|
|
443
489
|
)
|
|
444
490
|
|
|
445
491
|
|
|
492
|
+
def test_add_dynamic_vector_flip_dtype_all_zeros():
|
|
493
|
+
dp = create_datapackage()
|
|
494
|
+
flip_array = np.array([0, 0, 0]) # all falsy, but wrong dtype
|
|
495
|
+
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
496
|
+
with pytest.raises(WrongDatatype):
|
|
497
|
+
dp.add_dynamic_vector(
|
|
498
|
+
matrix="sa_matrix",
|
|
499
|
+
interface=Dummy(),
|
|
500
|
+
name="sa-data-vector",
|
|
501
|
+
flip_array=flip_array,
|
|
502
|
+
indices_array=indices_array,
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
|
|
446
506
|
def test_add_dynamic_vector_flip_shapemistmatch():
|
|
447
507
|
dp = create_datapackage()
|
|
448
508
|
flip_array = np.array([0, 1, 0, 1], dtype=bool)
|
|
@@ -457,28 +517,28 @@ def test_add_dynamic_vector_flip_shapemistmatch():
|
|
|
457
517
|
)
|
|
458
518
|
|
|
459
519
|
|
|
460
|
-
def
|
|
520
|
+
def test_add_persistent_vector_rescale_array():
|
|
461
521
|
dp = create_datapackage()
|
|
462
522
|
data_array = np.array([2.0, 7.0, 12.0])
|
|
463
|
-
|
|
523
|
+
rescale_array = np.array([0.5, 1.0, 2.0])
|
|
464
524
|
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
465
525
|
dp.add_persistent_vector(
|
|
466
526
|
matrix="sa_matrix",
|
|
467
527
|
data_array=data_array,
|
|
468
528
|
name="sa-data-vector",
|
|
469
529
|
indices_array=indices_array,
|
|
470
|
-
|
|
530
|
+
rescale_array=rescale_array,
|
|
471
531
|
)
|
|
472
|
-
assert "sa-data-vector.
|
|
473
|
-
data, meta = dp.get_resource("sa-data-vector.
|
|
474
|
-
assert meta["kind"] == "
|
|
475
|
-
assert np.allclose(data,
|
|
532
|
+
assert "sa-data-vector.rescale" in [o["name"] for o in dp.resources]
|
|
533
|
+
data, meta = dp.get_resource("sa-data-vector.rescale")
|
|
534
|
+
assert meta["kind"] == "rescale"
|
|
535
|
+
assert np.allclose(data, rescale_array)
|
|
476
536
|
|
|
477
537
|
|
|
478
538
|
def test_add_persistent_vector_scale_dtype():
|
|
479
539
|
dp = create_datapackage()
|
|
480
540
|
data_array = np.array([2.0, 7.0, 12.0])
|
|
481
|
-
|
|
541
|
+
rescale_array = np.array([1, 2, 3]) # integer dtype
|
|
482
542
|
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
483
543
|
with pytest.raises(WrongDatatype):
|
|
484
544
|
dp.add_persistent_vector(
|
|
@@ -486,14 +546,14 @@ def test_add_persistent_vector_scale_dtype():
|
|
|
486
546
|
data_array=data_array,
|
|
487
547
|
name="sa-data-vector",
|
|
488
548
|
indices_array=indices_array,
|
|
489
|
-
|
|
549
|
+
rescale_array=rescale_array,
|
|
490
550
|
)
|
|
491
551
|
|
|
492
552
|
|
|
493
553
|
def test_add_persistent_vector_scale_shapemismatch():
|
|
494
554
|
dp = create_datapackage()
|
|
495
555
|
data_array = np.array([2.0, 7.0, 12.0])
|
|
496
|
-
|
|
556
|
+
rescale_array = np.array([0.5, 1.0, 2.0, 3.0])
|
|
497
557
|
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
498
558
|
with pytest.raises(ShapeMismatch):
|
|
499
559
|
dp.add_persistent_vector(
|
|
@@ -501,32 +561,32 @@ def test_add_persistent_vector_scale_shapemismatch():
|
|
|
501
561
|
data_array=data_array,
|
|
502
562
|
name="sa-data-vector",
|
|
503
563
|
indices_array=indices_array,
|
|
504
|
-
|
|
564
|
+
rescale_array=rescale_array,
|
|
505
565
|
)
|
|
506
566
|
|
|
507
567
|
|
|
508
|
-
def
|
|
568
|
+
def test_add_persistent_array_rescale_array():
|
|
509
569
|
dp = create_datapackage()
|
|
510
570
|
data_array = np.arange(12, dtype=float).reshape(3, 4)
|
|
511
|
-
|
|
571
|
+
rescale_array = np.array([0.5, 1.0, 2.0])
|
|
512
572
|
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
513
573
|
dp.add_persistent_array(
|
|
514
574
|
matrix="sa_matrix",
|
|
515
575
|
data_array=data_array,
|
|
516
576
|
name="sa-data-vector",
|
|
517
577
|
indices_array=indices_array,
|
|
518
|
-
|
|
578
|
+
rescale_array=rescale_array,
|
|
519
579
|
)
|
|
520
|
-
assert "sa-data-vector.
|
|
521
|
-
data, meta = dp.get_resource("sa-data-vector.
|
|
522
|
-
assert meta["kind"] == "
|
|
523
|
-
assert np.allclose(data,
|
|
580
|
+
assert "sa-data-vector.rescale" in [o["name"] for o in dp.resources]
|
|
581
|
+
data, meta = dp.get_resource("sa-data-vector.rescale")
|
|
582
|
+
assert meta["kind"] == "rescale"
|
|
583
|
+
assert np.allclose(data, rescale_array)
|
|
524
584
|
|
|
525
585
|
|
|
526
586
|
def test_add_persistent_array_scale_dtype():
|
|
527
587
|
dp = create_datapackage()
|
|
528
588
|
data_array = np.arange(12, dtype=float).reshape(3, 4)
|
|
529
|
-
|
|
589
|
+
rescale_array = np.array([1, 2, 3])
|
|
530
590
|
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
531
591
|
with pytest.raises(WrongDatatype):
|
|
532
592
|
dp.add_persistent_array(
|
|
@@ -534,14 +594,14 @@ def test_add_persistent_array_scale_dtype():
|
|
|
534
594
|
data_array=data_array,
|
|
535
595
|
name="sa-data-vector",
|
|
536
596
|
indices_array=indices_array,
|
|
537
|
-
|
|
597
|
+
rescale_array=rescale_array,
|
|
538
598
|
)
|
|
539
599
|
|
|
540
600
|
|
|
541
601
|
def test_add_persistent_array_scale_shapemismatch():
|
|
542
602
|
dp = create_datapackage()
|
|
543
603
|
data_array = np.arange(12, dtype=float).reshape(3, 4)
|
|
544
|
-
|
|
604
|
+
rescale_array = np.array([0.5, 1.0, 2.0, 3.0])
|
|
545
605
|
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
546
606
|
with pytest.raises(ShapeMismatch):
|
|
547
607
|
dp.add_persistent_array(
|
|
@@ -549,30 +609,30 @@ def test_add_persistent_array_scale_shapemismatch():
|
|
|
549
609
|
data_array=data_array,
|
|
550
610
|
name="sa-data-vector",
|
|
551
611
|
indices_array=indices_array,
|
|
552
|
-
|
|
612
|
+
rescale_array=rescale_array,
|
|
553
613
|
)
|
|
554
614
|
|
|
555
615
|
|
|
556
|
-
def
|
|
616
|
+
def test_add_dynamic_vector_rescale_array():
|
|
557
617
|
dp = create_datapackage()
|
|
558
|
-
|
|
618
|
+
rescale_array = np.array([0.5, 1.0, 2.0])
|
|
559
619
|
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
560
620
|
dp.add_dynamic_vector(
|
|
561
621
|
matrix="sa_matrix",
|
|
562
622
|
interface=Dummy(),
|
|
563
623
|
name="sa-data-vector",
|
|
564
624
|
indices_array=indices_array,
|
|
565
|
-
|
|
625
|
+
rescale_array=rescale_array,
|
|
566
626
|
)
|
|
567
|
-
assert "sa-data-vector.
|
|
568
|
-
data, meta = dp.get_resource("sa-data-vector.
|
|
569
|
-
assert meta["kind"] == "
|
|
570
|
-
assert np.allclose(data,
|
|
627
|
+
assert "sa-data-vector.rescale" in [o["name"] for o in dp.resources]
|
|
628
|
+
data, meta = dp.get_resource("sa-data-vector.rescale")
|
|
629
|
+
assert meta["kind"] == "rescale"
|
|
630
|
+
assert np.allclose(data, rescale_array)
|
|
571
631
|
|
|
572
632
|
|
|
573
633
|
def test_add_dynamic_vector_scale_dtype():
|
|
574
634
|
dp = create_datapackage()
|
|
575
|
-
|
|
635
|
+
rescale_array = np.array([1, 2, 3])
|
|
576
636
|
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
577
637
|
with pytest.raises(WrongDatatype):
|
|
578
638
|
dp.add_dynamic_vector(
|
|
@@ -580,13 +640,13 @@ def test_add_dynamic_vector_scale_dtype():
|
|
|
580
640
|
interface=Dummy(),
|
|
581
641
|
name="sa-data-vector",
|
|
582
642
|
indices_array=indices_array,
|
|
583
|
-
|
|
643
|
+
rescale_array=rescale_array,
|
|
584
644
|
)
|
|
585
645
|
|
|
586
646
|
|
|
587
647
|
def test_add_dynamic_vector_scale_shapemismatch():
|
|
588
648
|
dp = create_datapackage()
|
|
589
|
-
|
|
649
|
+
rescale_array = np.array([0.5, 1.0, 2.0, 3.0])
|
|
590
650
|
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
591
651
|
with pytest.raises(ShapeMismatch):
|
|
592
652
|
dp.add_dynamic_vector(
|
|
@@ -594,30 +654,30 @@ def test_add_dynamic_vector_scale_shapemismatch():
|
|
|
594
654
|
interface=Dummy(),
|
|
595
655
|
name="sa-data-vector",
|
|
596
656
|
indices_array=indices_array,
|
|
597
|
-
|
|
657
|
+
rescale_array=rescale_array,
|
|
598
658
|
)
|
|
599
659
|
|
|
600
660
|
|
|
601
|
-
def
|
|
661
|
+
def test_add_dynamic_array_rescale_array():
|
|
602
662
|
dp = create_datapackage()
|
|
603
|
-
|
|
663
|
+
rescale_array = np.array([0.5, 1.0, 2.0])
|
|
604
664
|
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
605
665
|
dp.add_dynamic_array(
|
|
606
666
|
matrix="sa_matrix",
|
|
607
667
|
interface=Dummy(),
|
|
608
668
|
name="sa-data-vector",
|
|
609
669
|
indices_array=indices_array,
|
|
610
|
-
|
|
670
|
+
rescale_array=rescale_array,
|
|
611
671
|
)
|
|
612
|
-
assert "sa-data-vector.
|
|
613
|
-
data, meta = dp.get_resource("sa-data-vector.
|
|
614
|
-
assert meta["kind"] == "
|
|
615
|
-
assert np.allclose(data,
|
|
672
|
+
assert "sa-data-vector.rescale" in [o["name"] for o in dp.resources]
|
|
673
|
+
data, meta = dp.get_resource("sa-data-vector.rescale")
|
|
674
|
+
assert meta["kind"] == "rescale"
|
|
675
|
+
assert np.allclose(data, rescale_array)
|
|
616
676
|
|
|
617
677
|
|
|
618
678
|
def test_add_dynamic_array_scale_dtype():
|
|
619
679
|
dp = create_datapackage()
|
|
620
|
-
|
|
680
|
+
rescale_array = np.array([1, 2, 3])
|
|
621
681
|
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
622
682
|
with pytest.raises(WrongDatatype):
|
|
623
683
|
dp.add_dynamic_array(
|
|
@@ -625,13 +685,13 @@ def test_add_dynamic_array_scale_dtype():
|
|
|
625
685
|
interface=Dummy(),
|
|
626
686
|
name="sa-data-vector",
|
|
627
687
|
indices_array=indices_array,
|
|
628
|
-
|
|
688
|
+
rescale_array=rescale_array,
|
|
629
689
|
)
|
|
630
690
|
|
|
631
691
|
|
|
632
692
|
def test_add_dynamic_array_scale_shapemismatch():
|
|
633
693
|
dp = create_datapackage()
|
|
634
|
-
|
|
694
|
+
rescale_array = np.array([0.5, 1.0, 2.0, 3.0])
|
|
635
695
|
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
636
696
|
with pytest.raises(ShapeMismatch):
|
|
637
697
|
dp.add_dynamic_array(
|
|
@@ -639,7 +699,7 @@ def test_add_dynamic_array_scale_shapemismatch():
|
|
|
639
699
|
interface=Dummy(),
|
|
640
700
|
name="sa-data-vector",
|
|
641
701
|
indices_array=indices_array,
|
|
642
|
-
|
|
702
|
+
rescale_array=rescale_array,
|
|
643
703
|
)
|
|
644
704
|
|
|
645
705
|
|
|
@@ -782,8 +842,8 @@ def test_finalize_mixed_groups_prunes_only_trivial(tmp_path):
|
|
|
782
842
|
assert dist_resources[0]["group"] == "real"
|
|
783
843
|
|
|
784
844
|
|
|
785
|
-
def
|
|
786
|
-
|
|
845
|
+
def test_rescale_array_parquet_roundtrip(tmp_path):
|
|
846
|
+
rescale_array = np.array([0.5, 1.0, 2.0])
|
|
787
847
|
indices_array = np.array([(1, 4), (2, 5), (3, 6)], dtype=INDICES_DTYPE)
|
|
788
848
|
data_array = np.array([100.0, 200.0, 300.0])
|
|
789
849
|
|
|
@@ -796,16 +856,16 @@ def test_scale_array_parquet_roundtrip(tmp_path):
|
|
|
796
856
|
data_array=data_array,
|
|
797
857
|
name="sa-data-vector",
|
|
798
858
|
indices_array=indices_array,
|
|
799
|
-
|
|
859
|
+
rescale_array=rescale_array,
|
|
800
860
|
matrix_serialize_format_type=MatrixSerializeFormat.PARQUET,
|
|
801
861
|
)
|
|
802
862
|
dp.finalize_serialization()
|
|
803
863
|
|
|
804
864
|
dp2 = load_datapackage(generic_directory_filesystem(dirpath=tmp_path))
|
|
805
|
-
assert "sa-data-vector.
|
|
806
|
-
loaded, meta = dp2.get_resource("sa-data-vector.
|
|
807
|
-
assert meta["kind"] == "
|
|
808
|
-
assert np.allclose(loaded,
|
|
865
|
+
assert "sa-data-vector.rescale" in [o["name"] for o in dp2.resources]
|
|
866
|
+
loaded, meta = dp2.get_resource("sa-data-vector.rescale")
|
|
867
|
+
assert meta["kind"] == "rescale"
|
|
868
|
+
assert np.allclose(loaded, rescale_array)
|
|
809
869
|
|
|
810
870
|
|
|
811
871
|
def test_simple_graph():
|
|
@@ -49,6 +49,15 @@ class TestMatrixEntry:
|
|
|
49
49
|
assert math.isnan(e.shape)
|
|
50
50
|
assert math.isnan(e.minimum)
|
|
51
51
|
assert math.isnan(e.maximum)
|
|
52
|
+
assert e.rescale == pytest.approx(1.0)
|
|
53
|
+
|
|
54
|
+
def test_rescale_custom_value(self):
|
|
55
|
+
e = MatrixEntry(row=1, col=2, amount=3.0, rescale=0.5)
|
|
56
|
+
assert e.rescale == pytest.approx(0.5)
|
|
57
|
+
|
|
58
|
+
def test_rescale_in_as_dict(self):
|
|
59
|
+
e = MatrixEntry(row=1, col=2, amount=3.0, rescale=2.0)
|
|
60
|
+
assert e.as_dict()["rescale"] == pytest.approx(2.0)
|
|
52
61
|
|
|
53
62
|
def test_loc_set_to_amount_for_no_uncertainty(self):
|
|
54
63
|
e = MatrixEntry(row=1, col=2, amount=5.0)
|
|
@@ -81,6 +90,7 @@ class TestMatrixEntry:
|
|
|
81
90
|
assert set(d.keys()) == {
|
|
82
91
|
"row", "col", "amount", "flip", "uncertainty_type",
|
|
83
92
|
"loc", "scale", "shape", "minimum", "maximum", "negative",
|
|
93
|
+
"rescale",
|
|
84
94
|
}
|
|
85
95
|
|
|
86
96
|
def test_as_dict_values(self):
|
|
@@ -228,6 +238,19 @@ class TestArrayEntry:
|
|
|
228
238
|
with pytest.raises(ValueError, match="flip.*rows"):
|
|
229
239
|
ArrayEntry(rows=[0, 1], cols=[2, 3], data=np.ones((2, 4)), flip=[True, False, True])
|
|
230
240
|
|
|
241
|
+
def test_rescale_default_is_none(self):
|
|
242
|
+
e = ArrayEntry(rows=[0, 1], cols=[2, 3], data=np.ones((2, 4)))
|
|
243
|
+
assert e.rescale is None
|
|
244
|
+
|
|
245
|
+
def test_rescale_coerced_to_float32(self):
|
|
246
|
+
e = ArrayEntry(rows=[0, 1], cols=[2, 3], data=np.ones((2, 4)), rescale=[2.0, 0.5])
|
|
247
|
+
assert e.rescale.dtype == np.float32
|
|
248
|
+
np.testing.assert_array_almost_equal(e.rescale, [2.0, 0.5])
|
|
249
|
+
|
|
250
|
+
def test_rescale_shape_mismatch(self):
|
|
251
|
+
with pytest.raises(ValueError, match="rescale.*rows"):
|
|
252
|
+
ArrayEntry(rows=[0, 1], cols=[2, 3], data=np.ones((2, 4)), rescale=[1.0, 2.0, 3.0])
|
|
253
|
+
|
|
231
254
|
|
|
232
255
|
class TestAddArrayEntries:
|
|
233
256
|
def test_single_entry(self):
|
|
@@ -285,6 +308,86 @@ class TestAddArrayEntries:
|
|
|
285
308
|
kinds = [r["kind"] for r in group.resources]
|
|
286
309
|
assert "flip" not in kinds
|
|
287
310
|
|
|
311
|
+
def test_no_rescale_resource_when_rescale_is_none(self):
|
|
312
|
+
dp = create_datapackage()
|
|
313
|
+
entry = ArrayEntry(rows=[0, 1], cols=[2, 3], data=np.ones((2, 3)))
|
|
314
|
+
dp.add_array_entries(matrix="technosphere_matrix", entries=[entry])
|
|
315
|
+
group = next(iter(dp.groups.values()))
|
|
316
|
+
kinds = [r["kind"] for r in group.resources]
|
|
317
|
+
assert "rescale" not in kinds
|
|
318
|
+
|
|
319
|
+
def test_rescale_stored_correctly(self):
|
|
320
|
+
dp = create_datapackage()
|
|
321
|
+
entry = ArrayEntry(rows=[0, 1], cols=[2, 3], data=np.ones((2, 3)), rescale=[2.0, 0.5])
|
|
322
|
+
dp.add_array_entries(matrix="technosphere_matrix", entries=[entry])
|
|
323
|
+
group = next(iter(dp.groups.values()))
|
|
324
|
+
rescale_resource = next(r for r in group.resources if r["kind"] == "rescale")
|
|
325
|
+
stored = dp.data[dp.resources.index(rescale_resource)]
|
|
326
|
+
np.testing.assert_array_almost_equal(stored, [2.0, 0.5])
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
class TestAddEntries:
|
|
330
|
+
def test_no_rescale_resource_when_all_rescale_one(self):
|
|
331
|
+
dp = create_datapackage()
|
|
332
|
+
entries = [
|
|
333
|
+
MatrixEntry(row=1, col=2, amount=1.0),
|
|
334
|
+
MatrixEntry(row=3, col=4, amount=2.0),
|
|
335
|
+
]
|
|
336
|
+
dp.add_entries(matrix="technosphere_matrix", entries=entries)
|
|
337
|
+
group = next(iter(dp.groups.values()))
|
|
338
|
+
kinds = [r["kind"] for r in group.resources]
|
|
339
|
+
assert "rescale" not in kinds
|
|
340
|
+
|
|
341
|
+
def test_rescale_resource_stored_when_rescale_set(self):
|
|
342
|
+
dp = create_datapackage()
|
|
343
|
+
entries = [
|
|
344
|
+
MatrixEntry(row=1, col=2, amount=1.0, rescale=0.5),
|
|
345
|
+
MatrixEntry(row=3, col=4, amount=2.0, rescale=2.0),
|
|
346
|
+
]
|
|
347
|
+
dp.add_entries(matrix="technosphere_matrix", entries=entries)
|
|
348
|
+
group = next(iter(dp.groups.values()))
|
|
349
|
+
rescale_resource = next(r for r in group.resources if r["kind"] == "rescale")
|
|
350
|
+
stored = dp.data[dp.resources.index(rescale_resource)]
|
|
351
|
+
np.testing.assert_array_almost_equal(sorted(stored), [0.5, 2.0])
|
|
352
|
+
|
|
353
|
+
def test_rescale_resource_written_when_only_some_entries_rescaled(self):
|
|
354
|
+
dp = create_datapackage()
|
|
355
|
+
entries = [
|
|
356
|
+
MatrixEntry(row=1, col=2, amount=1.0), # rescale=1.0 (default)
|
|
357
|
+
MatrixEntry(row=3, col=4, amount=2.0, rescale=0.5),
|
|
358
|
+
]
|
|
359
|
+
dp.add_entries(matrix="technosphere_matrix", entries=entries)
|
|
360
|
+
group = next(iter(dp.groups.values()))
|
|
361
|
+
idx_resource = next(r for r in group.resources if r["kind"] == "indices")
|
|
362
|
+
rescale_resource = next(r for r in group.resources if r["kind"] == "rescale")
|
|
363
|
+
indices = dp.data[dp.resources.index(idx_resource)]
|
|
364
|
+
rescales = dp.data[dp.resources.index(rescale_resource)]
|
|
365
|
+
for i, idx in enumerate(indices):
|
|
366
|
+
if idx["row"] == 1:
|
|
367
|
+
assert rescales[i] == pytest.approx(1.0)
|
|
368
|
+
else:
|
|
369
|
+
assert rescales[i] == pytest.approx(0.5)
|
|
370
|
+
|
|
371
|
+
def test_rescale_sorted_with_data(self):
|
|
372
|
+
dp = create_datapackage()
|
|
373
|
+
entries = [
|
|
374
|
+
MatrixEntry(row=3, col=4, amount=2.0, rescale=2.0),
|
|
375
|
+
MatrixEntry(row=1, col=2, amount=1.0, rescale=0.5),
|
|
376
|
+
]
|
|
377
|
+
dp.add_entries(matrix="technosphere_matrix", entries=entries)
|
|
378
|
+
group = next(iter(dp.groups.values()))
|
|
379
|
+
|
|
380
|
+
idx_resource = next(r for r in group.resources if r["kind"] == "indices")
|
|
381
|
+
rescale_resource = next(r for r in group.resources if r["kind"] == "rescale")
|
|
382
|
+
indices = dp.data[dp.resources.index(idx_resource)]
|
|
383
|
+
rescales = dp.data[dp.resources.index(rescale_resource)]
|
|
384
|
+
|
|
385
|
+
for i, idx in enumerate(indices):
|
|
386
|
+
if idx["row"] == 1:
|
|
387
|
+
assert rescales[i] == pytest.approx(0.5)
|
|
388
|
+
else:
|
|
389
|
+
assert rescales[i] == pytest.approx(2.0)
|
|
390
|
+
|
|
288
391
|
|
|
289
392
|
class TestSimpleGraphDeprecation:
|
|
290
393
|
def test_deprecation_warning(self):
|
|
@@ -37,7 +37,7 @@ def test_dictionary_formatter_sparse():
|
|
|
37
37
|
result = dictionary_formatter(given)
|
|
38
38
|
assert result[:5] == (1, 1, 4, 0, 4)
|
|
39
39
|
assert all(np.isnan(x) for x in result[5:9])
|
|
40
|
-
assert result[9:] == (False, False)
|
|
40
|
+
assert result[9:] == (False, False, 1.0)
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
def test_dictionary_formatter_uncertainty_type():
|
|
@@ -68,7 +68,7 @@ def test_dictionary_formatter_complete():
|
|
|
68
68
|
"negative": True,
|
|
69
69
|
"flip": False,
|
|
70
70
|
}
|
|
71
|
-
expected = (1, 2, 3, 4, 5, 6, 7, 8, 9, True, False)
|
|
71
|
+
expected = (1, 2, 3, 4, 5, 6, 7, 8, 9, True, False, 1.0)
|
|
72
72
|
assert dictionary_formatter(given) == expected
|
|
73
73
|
|
|
74
74
|
|
|
@@ -85,10 +85,22 @@ def test_dictionary_formatter_one_dimensional():
|
|
|
85
85
|
"negative": True,
|
|
86
86
|
"flip": False,
|
|
87
87
|
}
|
|
88
|
-
expected = (1, 1, 3, 4, 5, 6, 7, 8, 9, True, False)
|
|
88
|
+
expected = (1, 1, 3, 4, 5, 6, 7, 8, 9, True, False, 1.0)
|
|
89
89
|
assert dictionary_formatter(given) == expected
|
|
90
90
|
|
|
91
91
|
|
|
92
|
+
def test_dictionary_formatter_rescale():
|
|
93
|
+
given = {"row": 1, "col": 2, "amount": 3.0, "rescale": 0.5}
|
|
94
|
+
result = dictionary_formatter(given)
|
|
95
|
+
assert result[-1] == 0.5
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def test_dictionary_formatter_rescale_default():
|
|
99
|
+
given = {"row": 1, "amount": 4}
|
|
100
|
+
result = dictionary_formatter(given)
|
|
101
|
+
assert result[-1] == 1.0
|
|
102
|
+
|
|
103
|
+
|
|
92
104
|
def test_check_suffix():
|
|
93
105
|
assert check_suffix("foo.bar.baz", "baz") == "foo.bar.baz"
|
|
94
106
|
assert check_suffix("foo.bar.baz", ".baz") == "foo.bar.baz"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|