Error when using to_homo and to_block together

I encountered an error when converting a hetero graph returned by to_block to a homo graph using to_homo. The following code reproduces the error:

hg = dgl.heterograph({
    ('user', 'follows', 'user'): ([0,1,2], [1,2,3]),
    ('user', 'buys', 'item'): ([0,1,2], [2,1,0])
})
dst_nodes = {
    'user': th.tensor([2]),
    'item': th.tensor([1,2])
}
block = dgl.to_block(hg, dst_nodes )
g = dgl.to_homo(block)

Error message:

DGLError: Expect number of features to match number of nodes (len(u)). Got 8 and 10 instead.

Did I use the two APIs incorrectly? Why does to_homo not work in this case?

Hi,

Were you trying to make the block a homogeneous graph? Could you tell what is your expected g from your example?

Thanks.

Yes. I expect that g should have the number of nodes equal to the sum of the number of src and dst nodes in block. The edges in g are those edges from src to dst in block.
The following function does what I expect dgl.to_homo to do.

def block_to_homo(block):
    g = dgl.DGLGraph()
    num_nodes = sum([block.number_of_src_nodes(ntype) for ntype in block.srctypes]) + \
        sum([block.number_of_dst_nodes(ntype) for ntype in block.dsttypes])
    g.add_nodes(num_nodes)
    num_src_types = len(block.srctypes)
    nid_offset = [0]


    n_type_ft = []
    n_id_ft = []

    for i, utype in enumerate(block.srctypes):
        nid_offset.append(nid_offset[-1] + block.number_of_src_nodes(utype))
        n_type_ft.append(th.tensor([i] * block.number_of_src_nodes(utype)))
        n_id_ft.append(th.arange(block.number_of_src_nodes(utype)))
    for i, vtype in enumerate(block.dsttypes):
        nid_offset.append(nid_offset[-1] + block.number_of_src_nodes(vtype))
        n_type_ft.append(th.tensor([i + num_src_types] * block.number_of_dst_nodes(vtype)))
        n_id_ft.append(th.arange(block.number_of_dst_nodes(vtype)))

    ndata = {
        dgl.NTYPE: th.cat(n_type_ft),
        dgl.NID: th.cat(n_id_ft)
    }
    g.ndata.update(ndata)

    e_type_ft = []
    e_id_ft = []
    for i, (utype, etype, vtype) in enumerate(block.canonical_etypes):
        uid, vid = block[etype].edges()
        uid = uid + nid_offset[block.get_ntype_id_from_src(utype)]
        vid = vid + nid_offset[block.get_ntype_id_from_dst(vtype)]
        g.add_edges(uid, vid)
        e_type_ft.append(th.tensor([i] * block.number_of_edges(etype)))
        e_id_ft.append(th.arange(block.number_of_edges(etype)))

    edata = {
        dgl.ETYPE: th.cat(e_type_ft),
        dgl.EID: th.cat(e_id_ft)
    }
    g.edata.update(edata)
    return g

We could convert the homo graph block_to_homo(block) to a hetero graph block2 and block2 is the same as block.

g = block_to_homo(block)
# I want to use 'SRC/' and 'DST/' but that will cause errors in to_hetero
# so I change 'SRC/' to 'SRC.', and 'DST/' to 'DST.'
# I think to_hetero should suppport ntypes start with 'SRC/' and 'DST/'
ntypes = ['SRC.' + ntype for ntype in block.srctypes] + \
         ['DST.' + ntype for ntype in block.dsttypes]
etypes = block.etypes
block2 = dgl.to_hetero(g, ntypes, etypes)

# block and block2 have the same nodes and edges
for ntype in block.srctypes:
    assert block.number_of_src_nodes(ntype) == block2.number_of_src_nodes('SRC.' + ntype)
for ntype in block.dsttypes:
    assert block.number_of_dst_nodes(ntype) == block2.number_of_dst_nodes('DST.' + ntype)
for etype in block.etypes:
    print(block2[etype].edges())
    print(block[etype].edges())