Add complement edges to PacketSetManager (O(1) Not) - #129
Open
matthewtlam wants to merge 1 commit into
Open
Conversation
Implements the complement-edge (a.k.a. negative/complemented edge) BDD
optimization for the packet-set decision diagram, resolving the b/382380335
TODOs on `Not` and `Or`.
The top bit of `PacketSetHandle::node_index_` becomes a "complement" flag:
a handle with the bit set denotes the complement of the set denoted by the
same handle with the bit cleared. Consequences:
* `Not` is now a single bit flip: O(1), no allocation, no recursion, and the
`not_cache_` is gone.
* Only one leaf sentinel is needed (`kFullSet`); `kEmptySet` is a complement
edge to it.
* `Or`/`Xor` keep their De Morgan formulation but the `Not`s are free, so they
share `and_cache_` instead of needing their own memo table.
Canonical form (enforced centrally in `NodeToPacket`): a stored node's default
("else") edge is never a complement edge; if it would be, the whole node is
complemented instead and a complement edge to it is returned. This keeps
exactly one node per {set, complement} pair, so "same bits iff same set"
(and therefore O(1) `operator==` / hashing) still holds.
Recursion that descends into a node (`And`, `Exists`, `Contains`,
`GetConcretePacketsDfs`, `PacketTransformerManager::FromPacketSetHandle`,
the pretty-printers) pushes the parent edge's complement bit into the child
edges via the new `PacketSetManager::ChildEdge` helper.
The node-index space halves from ~2^32 to ~2^31 (~2.1B), still far above the
"millions, not billions" expectation.
`ToDot` now emits a single `T` terminal with complement edges drawn as dotted
arrowheads, plus an invisible `__root__` entry so a complemented root shows.
`packet_set_test.expected` regenerated; `packet_transformer_test.expected` is
unchanged (transformer behavior is byte-identical).
Tested: `bazel test //netkat/...` passes in both fastbuild (all debug
invariant checks + CheckInternalInvariants active) and -c opt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the complement-edge (a.k.a. negative/complemented edge) BDD optimization for the packet-set decision diagram, resolving the b/382380335 TODOs on
NotandOr.The top bit of
PacketSetHandle::node_index_becomes a "complement" flag: a handle with the bit set denotes the complement of the set denoted by the same handle with the bit cleared. Consequences:Notis now a single bit flip: O(1), no allocation, no recursion, and thenot_cache_is gone.kFullSet);kEmptySetis a complement edge to it.Or/Xorkeep their De Morgan formulation but theNots are free, so they shareand_cache_instead of needing their own memo table.Canonical form (enforced centrally in
NodeToPacket): a stored node's default ("else") edge is never a complement edge; if it would be, the whole node is complemented instead and a complement edge to it is returned. This keeps exactly one node per {set, complement} pair, so "same bits iff same set" (and therefore O(1)operator==/ hashing) still holds.Recursion that descends into a node (
And,Exists,Contains,GetConcretePacketsDfs,PacketTransformerManager::FromPacketSetHandle, the pretty-printers) pushes the parent edge's complement bit into the child edges via the newPacketSetManager::ChildEdgehelper.The node-index space halves from ~2^32 to ~2^31 (~2.1B), still far above the "millions, not billions" expectation.
ToDotnow emits a singleTterminal with complement edges drawn as dotted arrowheads, plus an invisible__root__entry so a complemented root shows.packet_set_test.expectedregenerated;packet_transformer_test.expectedis unchanged (transformer behavior is byte-identical).Tested:
bazel test //netkat/...passes in both fastbuild (all debug invariant checks + CheckInternalInvariants active) and -c opt.