Skip to content

fraig_store: restore the PI order when the name comparison fails - #538

Open
marcelwa wants to merge 1 commit into
berkeley-abc:masterfrom
marcelwa:fraig-store-restore-pi-order
Open

fraig_store: restore the PI order when the name comparison fails#538
marcelwa wants to merge 1 commit into
berkeley-abc:masterfrom
marcelwa:fraig-store-restore-pi-order

Conversation

@marcelwa

@marcelwa marcelwa commented Aug 7, 2026

Copy link
Copy Markdown

Follow-up to #537, which I filed before I had the mechanism right. It is not PI invention in Abc_NtkAppendToCone() — that branch is never reached here. It is PI reordering, one level up, and it has a two-line fix.

What happens

Abc_NtkCompareSignals() calls Abc_NtkOrderObjsByName() on both networks, which qsorts vPis, vPos and vBoxes in place before the comparison. That is deliberate: it is what lets fraig_store accept two networks that use the same port names in a different order.

When the names genuinely differ, the comparison fails and Abc_NtkFraigStore() takes this path:

if ( !Abc_NtkCompareSignals( pNtk, (Abc_Ntk_t *)Vec_PtrEntry(vStore, 0), 1, 1 ) )
{
    printf( "Trying to store the network with different primary inputs.\n" );
    printf( "The previously stored networks are deleted and this one is added.\n" );
    Abc_NtkFraigStoreClean();
}
Vec_PtrPush( vStore, pNtk );

The store is reset and pNtk is kept — but pNtk has already been sorted by the comparison that failed. What goes into the store is a permutation of the network the caller read in. The two printed lines say the store was reset; nothing says the interface changed.

Sorting is by name as a string, so numeric port names are the worst case: 1, 2, …, 10 sorts to 1, 10, 2, 3, ….

Reproducing

EPFL cavlc and its published reference netlist, whose ports are named 110:

read_aiger cavlc.aig;        strash; fraig_store
read_blif  cavlc_size.blif;  strash; fraig_store
fraig_restore; write_blif out.blif
$ abc -q "read_blif out.blif; print_io"
Primary inputs (10):  0=1 1=10 2=2 3=3 4=4 5=5 6=6 7=7 8=8 9=9
                            ^^^^ should be 1=2

$ abc -q "cec -n out.blif cavlc.aig"
Output po00: Value in Network1 = 0. Value in Network2 = 1.

Right number of inputs and outputs, passes Abc_NtkCheck(), wrong function. The reference netlist on its own is equivalent — only going through fraig_store breaks it, and only because the store then discards it and keeps the sorted copy.

I ran into this building choice networks out of differently-named implementations of the same circuit; 9 of 20 merges came back non-equivalent with plausible-looking area and depth. The workaround is to round-trip everything through write_aiger/read_aiger first so names are regenerated positionally, but the sort surviving a failed comparison seemed worth fixing rather than working around.

The change

Save vPis/vPos/vBoxes before the comparison, put them back if it fails, and rebuild vCis/vCos with Abc_NtkOrderCisCos().

Deliberately narrow:

  • The success path is untouched — when the names do line up, both networks stay sorted into the common order, which is the point.
  • Networks whose names already agree never reach Abc_NtkCompareSignals() at all, because Abc_NodeCompareCiCo() has already returned 1.
  • The warning still prints, and the store is still reset.

Checks

Built clean. Against the EPFL suite:

  • cavlc with the mismatched reference: PI order now 0=1 1=2 2=3 …, and cec -n reports equivalent.
  • ctrl, arbiter, max — names already agree — merge and verify exactly as before.
  • Same-interface merge, and a plain single-network fraig_store/fraig_restore, both unchanged.
  • The warning is still emitted on the mismatch path.

Happy to add the name-mismatch case to a regression test if you have a preferred place for it.

Abc_NtkCompareSignals() sorts the PIs, POs and boxes of both networks by name
before comparing them. That is deliberate and is what lets fraig_store accept
two networks that use the same names in a different order.

When the names do not match, though, the comparison fails, Abc_NtkFraigStore()
resets the store and keeps the incoming network -- which by then has already
been sorted. The network that ends up in the store is a permutation of the one
the caller read in, and nothing reports it. The two lines printed on that path
say the store was reset; they do not say the interface changed.

Sorting is by name as a string, so numeric port names are where it shows up
worst: 1, 2, ..., 10 sort as 1, 10, 2, 3, ... With the EPFL cavlc benchmark and
its published reference netlist, whose ports are named "1".."10",

    read_aiger cavlc.aig; strash; fraig_store
    read_blif  cavlc_size.blif; strash; fraig_store
    fraig_restore; write_blif out.blif

gives an out.blif whose inputs are ordered 1, 10, 2, 3, ... instead of
1, 2, 3, ..., 10. It has the right number of inputs and outputs, it passes
Abc_NtkCheck(), and "cec -n out.blif cavlc.aig" reports a counterexample.

Save the three vectors before the comparison and put them back if it fails,
then rebuild vCis/vCos with Abc_NtkOrderCisCos(). The success path is
untouched, and so is every path where the names already agree -- those never
reach Abc_NtkCompareSignals(), since Abc_NodeCompareCiCo() has already
returned 1.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant