@@ -2956,23 +2956,23 @@ impl PySparseObservable {
2956
2956
other : & Bound < ' py , PyAny > ,
2957
2957
) -> PyResult < Bound < ' py , PyAny > > {
2958
2958
let py = slf_. py ( ) ;
2959
- if slf_. is ( other) {
2959
+ let Some ( other) = coerce_to_observable ( other) ? else {
2960
+ return Ok ( py. NotImplemented ( ) . into_bound ( py) ) ;
2961
+ } ;
2962
+
2963
+ let other = other. borrow ( ) ;
2964
+ let slf_ = slf_. borrow ( ) ;
2965
+ if Arc :: ptr_eq ( & slf_. inner , & other. inner ) {
2960
2966
// This fast path is for consistency with the in-place `__iadd__`, which would otherwise
2961
2967
// struggle to do the addition to itself.
2962
- let slf_ = slf_. borrow ( ) ;
2963
2968
let inner = slf_. inner . read ( ) . map_err ( |_| InnerReadError ) ?;
2964
2969
return <& SparseObservable as :: std:: ops:: Mul < _ > >:: mul (
2965
2970
& inner,
2966
2971
Complex64 :: new ( 2.0 , 0.0 ) ,
2967
2972
)
2968
2973
. into_bound_py_any ( py) ;
2969
2974
}
2970
- let Some ( other) = coerce_to_observable ( other) ? else {
2971
- return Ok ( py. NotImplemented ( ) . into_bound ( py) ) ;
2972
- } ;
2973
- let slf_ = slf_. borrow ( ) ;
2974
2975
let slf_inner = slf_. inner . read ( ) . map_err ( |_| InnerReadError ) ?;
2975
- let other = other. borrow ( ) ;
2976
2976
let other_inner = other. inner . read ( ) . map_err ( |_| InnerReadError ) ?;
2977
2977
slf_inner. check_equal_qubits ( & other_inner) ?;
2978
2978
<& SparseObservable as :: std:: ops:: Add >:: add ( & slf_inner, & other_inner) . into_bound_py_any ( py)
@@ -2992,13 +2992,7 @@ impl PySparseObservable {
2992
2992
<& SparseObservable as :: std:: ops:: Add >:: add ( & other_inner, & inner) . into_bound_py_any ( py)
2993
2993
}
2994
2994
2995
- fn __iadd__ ( slf_ : Bound < Self > , other : & Bound < PyAny > ) -> PyResult < ( ) > {
2996
- if slf_. is ( other) {
2997
- let slf_ = slf_. borrow ( ) ;
2998
- let mut slf_inner = slf_. inner . write ( ) . map_err ( |_| InnerWriteError ) ?;
2999
- * slf_inner *= Complex64 :: new ( 2.0 , 0.0 ) ;
3000
- return Ok ( ( ) ) ;
3001
- }
2995
+ fn __iadd__ ( slf_ : Bound < PySparseObservable > , other : & Bound < PyAny > ) -> PyResult < ( ) > {
3002
2996
let Some ( other) = coerce_to_observable ( other) ? else {
3003
2997
// This is not well behaved - we _should_ return `NotImplemented` to Python space
3004
2998
// without an exception, but limitations in PyO3 prevent this at the moment. See
@@ -3008,9 +3002,18 @@ impl PySparseObservable {
3008
3002
other. repr( ) ?
3009
3003
) ) ) ;
3010
3004
} ;
3005
+
3006
+ let other = other. borrow ( ) ;
3011
3007
let slf_ = slf_. borrow ( ) ;
3012
3008
let mut slf_inner = slf_. inner . write ( ) . map_err ( |_| InnerWriteError ) ?;
3013
- let other = other. borrow ( ) ;
3009
+
3010
+ // Check if slf_ and other point to the same SparseObservable object, in which case
3011
+ // we just multiply it by 2
3012
+ if Arc :: ptr_eq ( & slf_. inner , & other. inner ) {
3013
+ * slf_inner *= Complex64 :: new ( 2.0 , 0.0 ) ;
3014
+ return Ok ( ( ) ) ;
3015
+ }
3016
+
3014
3017
let other_inner = other. inner . read ( ) . map_err ( |_| InnerReadError ) ?;
3015
3018
slf_inner. check_equal_qubits ( & other_inner) ?;
3016
3019
slf_inner. add_assign ( & other_inner) ;
@@ -3022,16 +3025,17 @@ impl PySparseObservable {
3022
3025
other : & Bound < ' py , PyAny > ,
3023
3026
) -> PyResult < Bound < ' py , PyAny > > {
3024
3027
let py = slf_. py ( ) ;
3025
- if slf_. is ( other) {
3026
- return PySparseObservable :: zero ( slf_. borrow ( ) . num_qubits ( ) ?) . into_bound_py_any ( py) ;
3027
- }
3028
3028
let Some ( other) = coerce_to_observable ( other) ? else {
3029
3029
return Ok ( py. NotImplemented ( ) . into_bound ( py) ) ;
3030
3030
} ;
3031
3031
3032
+ let other = other. borrow ( ) ;
3032
3033
let slf_ = slf_. borrow ( ) ;
3034
+ if Arc :: ptr_eq ( & slf_. inner , & other. inner ) {
3035
+ return PySparseObservable :: zero ( slf_. num_qubits ( ) ?) . into_bound_py_any ( py) ;
3036
+ }
3037
+
3033
3038
let slf_inner = slf_. inner . read ( ) . map_err ( |_| InnerReadError ) ?;
3034
- let other = other. borrow ( ) ;
3035
3039
let other_inner = other. inner . read ( ) . map_err ( |_| InnerReadError ) ?;
3036
3040
slf_inner. check_equal_qubits ( & other_inner) ?;
3037
3041
<& SparseObservable as :: std:: ops:: Sub >:: sub ( & slf_inner, & other_inner) . into_bound_py_any ( py)
@@ -3050,13 +3054,6 @@ impl PySparseObservable {
3050
3054
}
3051
3055
3052
3056
fn __isub__ ( slf_ : Bound < PySparseObservable > , other : & Bound < PyAny > ) -> PyResult < ( ) > {
3053
- if slf_. is ( other) {
3054
- // This is not strictly the same thing as `a - a` if `a` contains non-finite
3055
- // floating-point values (`inf - inf` is `NaN`, for example); we don't really have a
3056
- // clear view on what floating-point guarantees we're going to make right now.
3057
- slf_. borrow_mut ( ) . clear ( ) ?;
3058
- return Ok ( ( ) ) ;
3059
- }
3060
3057
let Some ( other) = coerce_to_observable ( other) ? else {
3061
3058
// This is not well behaved - we _should_ return `NotImplemented` to Python space
3062
3059
// without an exception, but limitations in PyO3 prevent this at the moment. See
@@ -3066,9 +3063,18 @@ impl PySparseObservable {
3066
3063
other. repr( ) ?
3067
3064
) ) ) ;
3068
3065
} ;
3066
+ let other = other. borrow ( ) ;
3069
3067
let slf_ = slf_. borrow ( ) ;
3070
3068
let mut slf_inner = slf_. inner . write ( ) . map_err ( |_| InnerWriteError ) ?;
3071
- let other = other. borrow ( ) ;
3069
+
3070
+ if Arc :: ptr_eq ( & slf_. inner , & other. inner ) {
3071
+ // This is not strictly the same thing as `a - a` if `a` contains non-finite
3072
+ // floating-point values (`inf - inf` is `NaN`, for example); we don't really have a
3073
+ // clear view on what floating-point guarantees we're going to make right now.
3074
+ slf_inner. clear ( ) ;
3075
+ return Ok ( ( ) ) ;
3076
+ }
3077
+
3072
3078
let other_inner = other. inner . read ( ) . map_err ( |_| InnerReadError ) ?;
3073
3079
slf_inner. check_equal_qubits ( & other_inner) ?;
3074
3080
slf_inner. sub_assign ( & other_inner) ;
0 commit comments