-
Notifications
You must be signed in to change notification settings - Fork 26
Description
I've found that creating an observer (from the package Observers.jl
) while ITensorInfiniteMPS
is loaded causes an error. This is because on line 130 of the file ITensors.jl
, you define a method for Base.copy
:
ITensorInfiniteMPS.jl/src/ITensors.jl
Line 130 in cc42d94
Base.copy(is::IndexSet) = IndexSet(copy.(ITensors.data(is))) |
However, in Observers.jl
, the constructor creates a dataframe with columns initialised to Union{}[]
, and in the process of creating this dataframe, these columns are copied. Since T <: Union{}
for all T
, and since an IndexSet = Vector{Index}
, technically Vector{Union{}} <: IndexSet
and it uses the new definition of Base.copy
. This immediately fails because, of course, this is not actually an index set and ITensors.data(is)
is undefined. I think essentially what's happened here is accidental type piracy.
MWE
Below is a MWE showing that that creating an observer works fine until ITensorInfiniteMPS
is loaded:
julia> using Observers
julia> obs = observer("foo" => (;) -> 1)
0×1 DataFrame
Row │ foo
│ Union{}
─────┴─────────
julia> using ITensors
julia> obs = observer("foo" => (;) -> 1)
0×1 DataFrame
Row │ foo
│ Union{}
─────┴─────────
julia> using ITensorMPS
julia> obs = observer("foo" => (;) -> 1)
0×1 DataFrame
Row │ foo
│ Union{}
─────┴─────────
julia> using ITensorInfiniteMPS
julia> obs = observer("foo" => (;) -> 1)
ERROR: MethodError: no method matching data(::Vector{Union{}})
The function `data` exists, but no method is defined for this combination of argument types.
Closest candidates are:
data(::InfiniteCanonicalMPS)
@ ITensorInfiniteMPS ...\ITensorInfiniteMPS\src\infinitemps.jl:35
data(::ITensor)
@ ITensors ...\ITensors\Zs2nC\src\itensor.jl:764
data(::CelledVector)
@ ITensorInfiniteMPS ...\ITensorInfiniteMPS\src\celledvectors.jl:78
...
Stacktrace:
[1] copy(is::Vector{Union{}})
@ ITensorInfiniteMPS ...\ITensorInfiniteMPS\src\ITensors.jl:130
[2] _preprocess_column(col::Vector{Union{}}, len::Int64, copycols::Bool)
@ DataFrames ...\DataFrames\kcA9R\src\dataframe\dataframe.jl:243
[3] DataFrames.DataFrame(columns::Vector{Any}, colindex::DataFrames.Index; copycols::Bool)
@ DataFrames ...\DataFrames\kcA9R\src\dataframe\dataframe.jl:227
[4] DataFrame
@ ...\DataFrames\kcA9R\src\dataframe\dataframe.jl:193 [inlined]
[5] DataFrames.DataFrame(pairs::Vector{Pair{String, Vector{Union{}}}}; makeunique::Bool, copycols::Bool)
@ DataFrames ...\DataFrames\kcA9R\src\dataframe\dataframe.jl:284
[6] DataFrame
@ ...\DataFrames\kcA9R\src\dataframe\dataframe.jl:274 [inlined]
[7] observer(names::Vector{String}, functions::Vector{var"#7#8"}; kwargs::@Kwargs{})
@ Observers ...\Observers\1ausc\src\observer.jl:9
[8] observer
@ ...\Observers\1ausc\src\observer.jl:8 [inlined]
[9] observer(names::Tuple{String}, functions::Tuple{var"#7#8"}; kwargs::@Kwargs{})
@ Observers ...\Observers\1ausc\src\observer.jl:17
[10] observer
@ ...\Observers\1ausc\src\observer.jl:16 [inlined]
[11] #observer#19
@ ...\Observers\1ausc\src\observer.jl:29 [inlined]
[12] observer(name_function_pairs::Pair{String, var"#7#8"})
@ ...\Observers\1ausc\src\observer.jl:28
[13] top-level scope
@ REPL[9]:1
NB: you can get the same stack trace with df = DataFrame("foo" => Union{}[])
Workarounds
- Define a generic fallback method,
ITensors.data(is) = is
, so thatBase.copy
works correctly on the empty column - Construct your observer as
observer(args; copycols=false)
, avoiding the use ofBase.copy
.