Catlab.jl icon indicating copy to clipboard operation
Catlab.jl copied to clipboard

return value of `add_parts!` not interacting well with `set_subpart!`

Open slwu89 opened this issue 2 years ago • 1 comments

Hi Catlab team,

I've observed some unexpected behavior when passing the result of add_parts! to set_subpart!. I've included an example below, when add_parts! is adding a single part to an Ob, it returns a 1:1 unit range, which set_subpart! doesn't like when it is used to set a Hom. However, using only (or something else) to turn the unit range into an Int gives the desired result.

@present ExSchema(FreeSchema) begin
    Ob1::Ob
    Ob2::Ob
    Fn::Hom(Ob1, Ob2)
end

@acset_type Example(ExSchema, unique_index = [:Fn])

ExampleInstance = Example()

add_parts!(ExampleInstance, :Ob1, 5)
ob2 = add_parts!(ExampleInstance, :Ob2, 1)

set_subpart!(ExampleInstance, 3, :Fn, ob2) # errors, ob2 is 1:1 unit range
set_subpart!(ExampleInstance, 3, :Fn, only(ob2)) # works as expected, converting to Int

I should note this problem only occurs when the result of add_parts! is a length 1 unit range, the following works fine:

ExampleInstance = Example()

add_parts!(ExampleInstance, :Ob1, 5)
ob2 = add_parts!(ExampleInstance, :Ob2, 2)

set_subpart!(ExampleInstance, [1, 3], :Fn, ob2)

The error occurs in the body of the generated function @assert 0 <= subpart <= acs.obs[$(ob_num(s, s.codoms[f]))], since subpart is a 1:1 unit range. Maybe one of the "higher level" functions in ACSetInterface.jl can deal with this case so the low level setter functions get the right data type?

I'm using Catlab 0.13.7

slwu89 avatar Mar 01 '22 02:03 slwu89

@epatters I just did some checking, adding this overload to CSetDataStructures.jl allows the preceding example to run as expected, and also does not cause any of the currently existing tests in the test suite to fail.

@inline ACSetInterface.set_subpart!(acs::StructACSet, part::Int, f::Symbol, subpart::T) where {T <: AbstractRange} =
  _set_subpart!(acs, part, Val{f}, length(subpart) > 1 ? subpart : only(subpart))

slwu89 avatar Mar 01 '22 18:03 slwu89

closing this issue, as it was a result of misunderstanding how to interact with the ACSet interface i.e; set_subpart!(ExampleInstance, [3], :Fn, ob2) works fine with the example code.

slwu89 avatar Aug 29 '22 03:08 slwu89