fraig_store / fraig_restore is the documented way to build a choice network out of several implementations of the same function. If those implementations disagree about their input names, the result is a well-formed network computing a different function, and nothing says so.
Abc_NtkAppendToCone() (src/base/abc/abcNtk.c, around line 1178) matches each CI of the incoming network to the accumulated one by name:
iNodeId = Nm_ManFindIdByNameTwoTypes( pNtkNew->pManName, Abc_ObjName(pObj), ABC_OBJ_PI, ABC_OBJ_BO );
if ( iNodeId == -1 )
{
pObj->pCopy = Abc_NtkCreatePi(pNtkNew);
Abc_ObjAssignName( pObj->pCopy, Abc_ObjName(pObj), NULL );
}
When the name is absent, a fresh primary input is created. So a structure whose inputs are called pi0 pi1 … merged onto one whose inputs are called 1 2 3 … is not merged onto the same variables at all — it is grafted onto a disjoint set of unconstrained ones. The accumulated network's input count grows, Abc_NtkCheck() passes, fraig_restore succeeds, and the mapper then picks cuts from a "choice" that is not equivalent to anything.
Reproducing
Take any circuit, write two structurally different implementations of it, name the ports differently in each, then:
read a.aig; strash; fraig_store
read b.blif; strash; fraig_store
fraig_restore; if -K 6; write_blif out.blif
cec -n out.blif original.aig
The workaround is easy once you know: round-trip every network through write_aiger/read_aiger first, which drops the symbol table and regenerates names positionally.
The question
Is the silent-PI-creation branch deliberate? I can see it being the right behaviour for Abc_NtkAppendToCone()'s other callers, where the incoming cone genuinely may reference signals the accumulator has not seen.
If it is deliberate, would a warning be acceptable when a CI name is not found during fraig_store accumulation — or a note in the fraig_store help text that the stored networks must agree on port names? The failure is silent and produces a plausible-looking result, which is the expensive kind.
Happy to send a patch for whichever of those you'd prefer.
fraig_store/fraig_restoreis the documented way to build a choice network out of several implementations of the same function. If those implementations disagree about their input names, the result is a well-formed network computing a different function, and nothing says so.Abc_NtkAppendToCone()(src/base/abc/abcNtk.c, around line 1178) matches each CI of the incoming network to the accumulated one by name:When the name is absent, a fresh primary input is created. So a structure whose inputs are called
pi0 pi1 …merged onto one whose inputs are called1 2 3 …is not merged onto the same variables at all — it is grafted onto a disjoint set of unconstrained ones. The accumulated network's input count grows,Abc_NtkCheck()passes,fraig_restoresucceeds, and the mapper then picks cuts from a "choice" that is not equivalent to anything.Reproducing
Take any circuit, write two structurally different implementations of it, name the ports differently in each, then:
The workaround is easy once you know: round-trip every network through
write_aiger/read_aigerfirst, which drops the symbol table and regenerates names positionally.The question
Is the silent-PI-creation branch deliberate? I can see it being the right behaviour for
Abc_NtkAppendToCone()'s other callers, where the incoming cone genuinely may reference signals the accumulator has not seen.If it is deliberate, would a warning be acceptable when a CI name is not found during
fraig_storeaccumulation — or a note in thefraig_storehelp text that the stored networks must agree on port names? The failure is silent and produces a plausible-looking result, which is the expensive kind.Happy to send a patch for whichever of those you'd prefer.