Skip to content

Commit fafc4c2

Browse files
committed
fix: handle numpy arrays and missing return cases in _combine_property
1 parent b71354a commit fafc4c2

File tree

1 file changed

+93
-0
lines changed
  • pymc_extras/statespace/models/structural

1 file changed

+93
-0
lines changed

pymc_extras/statespace/models/structural/core.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,99 @@ def _combine_property(self, other, name, allow_duplicates=True):
750750
new_prop.update(getattr(other, name))
751751
return new_prop
752752

753+
def _combine_property_2(self, other, name, allow_duplicates=True):
754+
"""
755+
Combine a property from two components during component addition.
756+
757+
This method handles the merging of component properties when two structural
758+
components are combined using the `+` operator. It handles different data types
759+
appropriately and provides control over duplicate handling for list properties.
760+
761+
Parameters
762+
----------
763+
other : Component
764+
The other component whose property is being combined with this one.
765+
name : str
766+
The name of the property to combine (e.g., 'state_names', 'param_names').
767+
allow_duplicates : bool, default True
768+
Controls duplicate handling for list properties:
769+
- True: Concatenates lists directly, preserving duplicates
770+
- False: Adds only items from `other` that aren't already in `self`
771+
772+
Returns
773+
-------
774+
Any
775+
Combined property value with type depending on the property type:
776+
- list: Concatenated lists (with or without deduplication)
777+
- dict: Merged dictionaries (other overwrites self for same keys)
778+
- scalar/array: Single value (if identical) or error (if different)
779+
780+
Raises
781+
------
782+
ValueError
783+
When scalar properties have different non-None values that cannot be
784+
automatically combined, indicating unclear user intent.
785+
"""
786+
self_prop = getattr(self, name)
787+
other_prop = getattr(other, name)
788+
789+
if isinstance(self_prop, list) and allow_duplicates:
790+
return self_prop + other_prop
791+
elif isinstance(self_prop, list) and not allow_duplicates:
792+
return self_prop + [x for x in other_prop if x not in self_prop]
793+
elif isinstance(self_prop, dict):
794+
new_prop = self_prop.copy()
795+
new_prop.update(other_prop)
796+
return new_prop
797+
else:
798+
# NEW: Handle cases where self_prop is not a list or dict
799+
import numpy as np
800+
801+
# Handle numpy arrays specially
802+
if isinstance(self_prop, np.ndarray) and isinstance(other_prop, np.ndarray):
803+
if np.array_equal(self_prop, other_prop):
804+
return self_prop
805+
else:
806+
# Convert to list for combination when arrays are different
807+
return (
808+
list(self_prop) + [x for x in other_prop if x not in self_prop]
809+
if not allow_duplicates
810+
else list(self_prop) + list(other_prop)
811+
)
812+
elif isinstance(self_prop, np.ndarray) or isinstance(other_prop, np.ndarray):
813+
# One is array, one is not - convert to list
814+
self_list = (
815+
list(self_prop)
816+
if isinstance(self_prop, np.ndarray)
817+
else [self_prop]
818+
if self_prop is not None
819+
else []
820+
)
821+
other_list = (
822+
list(other_prop)
823+
if isinstance(other_prop, np.ndarray)
824+
else [other_prop]
825+
if other_prop is not None
826+
else []
827+
)
828+
return (
829+
self_list + [x for x in other_list if x not in self_list]
830+
if not allow_duplicates
831+
else self_list + other_list
832+
)
833+
elif self_prop == other_prop:
834+
return self_prop
835+
elif self_prop is None and other_prop is not None:
836+
return other_prop
837+
elif self_prop is not None and other_prop is None:
838+
return self_prop
839+
else:
840+
# Different non-None values - this might indicate a problem
841+
raise ValueError(
842+
f"Cannot combine property '{name}': component values are different "
843+
f"({self_prop} vs {other_prop}) and cannot be automatically combined"
844+
)
845+
753846
def _combine_component_info(self, other):
754847
combined_info = {}
755848
for key, value in self._component_info.items():

0 commit comments

Comments
 (0)