@@ -254,6 +254,10 @@ def parent(self):
254254 -------
255255 Model
256256 """
257+ if '_parent' not in self .__dict__ :
258+ # This can be absent because of how serialization works.
259+ # It's set during deserialization in self.relink_parent().
260+ self ._parent = None
257261 return self ._parent
258262
259263 @parent .setter
@@ -308,11 +312,13 @@ def relink_parent(self, parent):
308312 None
309313 """
310314 for subm in self .submembers ():
311- subm .relink_parent (parent )
312-
313- if self ._parent is parent : return # OK to relink multiple times
314- assert (self ._parent is None ), "Cannot relink parent: parent is not None!"
315- self ._parent = parent # assume no dependent objects
315+ subm .relink_parent (parent )
316+ if '_parent' in self .__dict__ :
317+ # This codepath needed to resolve GitHub issue 651.
318+ if self ._parent is parent :
319+ return # OK to relink multiple times
320+ assert (self ._parent is None ), "Cannot relink parent: current parent is not None!"
321+ self ._parent = parent
316322
317323 def unlink_parent (self , force = False ):
318324 """
@@ -793,6 +799,9 @@ def copy(self, parent=None, memo=None):
793799 memo [id (self .parent )] = None # so deepcopy uses None instead of copying parent
794800 return self ._copy_gpindices (_copy .deepcopy (self , memo ), parent , memo )
795801
802+ def to_dense (self ) -> _np .ndarray :
803+ raise NotImplementedError ('Derived classes must implement .to_dense().' )
804+
796805 def _is_similar (self , other , rtol , atol ):
797806 """ Returns True if `other` model member (which it guaranteed to be the same type as self) has
798807 the same local structure, i.e., not considering parameter values or submembers """
@@ -857,7 +866,16 @@ def is_equivalent(self, other, rtol=1e-5, atol=1e-8):
857866 """
858867 if not self .is_similar (other ): return False
859868
860- if not _np .allclose (self .to_vector (), other .to_vector (), rtol = rtol , atol = atol ):
869+ try :
870+ v1 = self .to_vector ()
871+ v2 = other .to_vector ()
872+ except RuntimeError as e :
873+ if 'to_vector() should never be called' not in str (e ):
874+ raise e
875+ assert type (self ) == type (other )
876+ v1 = self .to_dense ()
877+ v2 = other .to_dense ()
878+ if not _np .allclose (v1 , v2 , rtol = rtol , atol = atol ):
861879 return False
862880
863881 # Recursive check on submembers
0 commit comments