Repository: sampsyo/cs6120
Pull request #532: [BLOG] Technology Mapping with Egraphs
Author: login: neel-patel-1
Labels: name: 2025sp
Created: 2025-05-13T08:26:09Z | Merged: 2025-05-18T13:48:12Z

closes #511 

Linked issue #511: Project Proposal: Testing Extraction Techniques for E-graph Based Digital Logic Rewriting
**What will you do?**

This project will aid in an ongoing effort to develop a framework for enhancing the synthesis of digital circuits. Optimization of RTL is a time-consuming, manual process.

Recent works propose representing an RTL specification of a circuit (written in verilog) as a graph and deploying modern graph rewriting techniques to automate the circuit design space exploration. Specifically, recent frameworks use e-graphs, which provide a dense representation of the design space and enable deferring the choice of circuit design until after a large set of equivalent candidates have been enumerated. E-graph-based frameworks have been shown to [construct higher-quality designs](https://arxiv.org/pdf/2403.14242) (e.g., area, latency) designs than existing EDA algorithms.

Although e-graphs provide a compact representation of many equivalent expressions (i.e., circuits), the process of extracting a design from the e-graph results in a tradeoff between time and quality of the resulting design. Existing works either use integer linear programming, which is not scalable to large designs, or greedy methods, which produce suboptimal designs.

In this project, we aim to evaluate emerging e-graph extraction techniques which are able to more favorably trade off scalability and resulting design cost.

We will integrate one or more e-graph extraction techniques in an e-graph-based RTL optimization framework and compare their performance in terms of the time it takes to perform the optimization and the cost of the resulting design. The first extraction method we plan to evaluate is [SmoothE](https://www.csl.cornell.edu/~zhiruz/pdfs/smoothe-asplos2025.pdf), which converts the discrete optimization problem of e-graph extraction into a differentiable e-graph extraction algorithm, which has been optimized to run on GPUs. At the same time, the existing ILP extractor, implemented in the [egg](https://github.com/egraphs-good/egg/blob/main/src/lp_extract.rs) library have not been integrated into the optimization framework, and would enable exploring a wider range of designs than the greedy algorithm currently deployed.

**How will you do it?**

1) Integrate and test an existing e-graph extraction technique in the e-graph library into an RTL-to-RTL superoptimizer.
2) Implement the SmoothE differentiable e-graph extraction algorithm in Rust to better integrate within the optimization framework – currently it is implemented in Python and uses the torch library to run operators on the GPU.
3) Run greedy, ILP, and SmoothE e-graph extraction algorithms on test RTL designs within the framework and report the cost of the resulting design in terms of LUTs and the time to optimize.
4) Consider alternative algorithms (e.g., genetic) which may strike a more favorable tradeoff between scalability and cost of the final design.
5) Time permitting, we will consider alternative e-graph extraction algorithms that may be better suited for RTL optimization through the use of domain-specific knowledge.


**How will you empirically measure success?**
We will test on some benchmarks – either actual RTL designs using the RTL optimization framework, or the benchmarks in egg’s extraction gym test suite. If we go the route of using RTL designs, this could be datasets such as ([lgsynth91, iscas85, and epfl](https://github.com/ispras/hdl-benchmarks)). There are a few cost functions we can choose such as circuit area or delay and we could evaluate the extent to which the rewrites using different extraction techniques improve these costs from their baseline.

**Team members:**
@arnavm30 
@neel-patel-1 

Linked issue comments: user: login: sampsyo
created_at: 2025-04-07T21:07:11Z
body: Let's get a little more specific here. When you say this:

> Integrate and test an existing e-graph extraction technique in the e-graph library into an RTL-to-RTL superoptimizer.

…you haven't specified which those are. Am I correct in surmising that you will apply Smooth-E extraction to E-Syn? As in, you will actually reuse the source code for those projects?

And when you say this:

> Implement the SmoothE differentiable e-graph extraction algorithm in Rust to better integrate within the optimization framework – currently it is implemented in Python and uses the torch library to run operators on the GPU.

What does it mean to port this to Rust? Are you still going to use the GPU? (And if so, how?) If it's just a CPU thing, how are you going to implement the tensor operators involved?

These steps are a bit too vague at this point; I would recommend just deciding now that you will not pursue them:

> 4. Consider alternative algorithms (e.g., genetic) which may strike a more favorable tradeoff between scalability and cost of the final design.
> 5. Time permitting, we will consider alternative e-graph extraction algorithms that may be better suited for RTL optimization through the use of domain-specific knowledge.

Namely, you haven't said what a "generic" approach to extraction would look like, nor do you provide examples of other extraction algorithms that you might try. This sounds like it would involve inventing whole new extraction approaches, which is almost certainly too much work for this short of a project.

I also don't understand this sentence:

> At the same time, the existing ILP extractor, implemented in the [egg](https://github.com/egraphs-good/egg/blob/main/src/lp_extract.rs) library have not been integrated into the optimization framework, and would enable exploring a wider range of designs than the greedy algorithm currently deployed.

What is "the optimization framework"? Are you saying that E-Syn doesn't use ILP extraction yet, and you want to try that?

One other thing in the evaluation plan:

> We will test on some benchmarks – either actual RTL designs using the RTL optimization framework, or the benchmarks in egg’s extraction gym test suite.

I don't get this: isn't the whole point of this project to apply the new extraction approach *to RTL synthesis*, not to e-graph extraction in general? Presumably, if the "extraction gym test suite" is the standard way to measure the efficiency of extraction, the extraction approaches have probably *already* been applied to this, right?
author_association: OWNER
user: login: neel-patel-1
created_at: 2025-04-09T03:33:51Z
body: > Am I correct in surmising that you will apply Smooth-E extraction to E-Syn? As in, you will actually reuse the source code for those projects?

In this project, we’re building on top of a different RTL Superoptimizer, which is written in Rust. Our plan is to apply Smooth-E extraction to that project. Currently, the project is private as it’s in submission, but would eventually be public. The SmoothE extractor would be implemented inside the egg library, and would therefore be public.

> What does it mean to port this to Rust? Are you still going to use the GPU? (And if so, how?) If it's just a CPU thing, how are you going to implement the tensor operators involved?

Because the RTL superoptimizer is written in rust and uses the egg library, we would like to use an extraction algorithm also implemented in egg. 

Using the current implementation of SmoothE would require converting the e-graph representation of the netlist to json and running the SmoothE extraction python script. Ideally, the entire flow would be written in Rust. We still aim to run SmoothE on a GPU, since much of its benefit comes from its ability to be parallelized. We believe the [torch bindings](https://github.com/LaurentMazare/tch-rs) for rust should make this possible.

> Namely, you haven't said what a "generic" approach to extraction would look like, nor do you provide examples of other extraction algorithms that you might try. This sounds like it would involve inventing whole new extraction approaches, which is almost certainly too much work for this short of a project.

We plan to only implement SmoothE and spend any remaining time evaluating its performance against other extraction algorithms.

> What is "the optimization framework"? Are you saying that E-Syn doesn't use ILP extraction yet, and you want to try that?

Egg’s current implementation of the ILP extractor does not support the cost models the RTL optimizer uses for RTL synthesis. When attempting to use the ILP extractor, it crashed.

> isn't the whole point of this project to apply the new extraction approach to RTL synthesis, not to e-graph extraction in general? Presumably, if the "extraction gym test suite" is the standard way to measure the efficiency of extraction, the extraction approaches have probably already been applied to this, right?

The goal of this project is to apply the new extraction technique to RTL synthesis. By implementing SmoothE in egg, we enable other projects to use the new extractor, and also enable easier comparison with extraction algorithms already implemented in egg.
author_association: CONTRIBUTOR
user: login: sampsyo
created_at: 2025-04-09T13:09:39Z
body: > In this project, we’re building on top of a different RTL Superoptimizer, which is written in Rust. Our plan is to apply Smooth-E extraction to that project. Currently, the project is private as it’s in submission, but would eventually be public.

Just so we're clear: do you already have access to this private code? (I just want to make sure that you're not stuck waiting for the project to become open-source before you can start work.)

I think I'm getting a somewhat clearer picture of what you're proposing here. I think what you're suggesting consists of the following deliverables:

1. Reimplement SmoothE in Rust, using `tch-rs`. (How will you test for correctness against the existing SmoothE?)
2. Take this unnamed RTL synthesis tool, which currently uses egg's greedy extractor, and make it use your new port of SmoothE instead.

Is that right? Am I missing anything?

If that's right, please try to distill a concrete empirical evaluation plan. Some things to think through:

* What metrics will you use to assess the SmoothE port on its own, if any? (Or maybe you're not planning on measuring this separately?)
* What metrics will you use to assess the changes to the RTL synthesis tool? (Extraction running time? Any metrics of synthesized circuit quality?)
* What baseline will you use for the RTL synthesis measurement? (Is it the original tool, using egg's greedy extraction?)
author_association: OWNER
user: login: neel-patel-1
created_at: 2025-04-10T16:01:12Z
body: > do you already have access to this private code?

Yes, we have already tested the framework for RTL superoptimization.

> I think what you're suggesting consists of the following deliverables
> Reimplement SmoothE in Rust, using tch-rs.
> Take this unnamed RTL synthesis tool, which currently uses egg's greedy extractor, and make it use your new port of SmoothE instead.

Currently, these are the deliverables we plan on providing.

> How will you test for correctness against the existing SmoothE?

We will also run the existing SmoothE superoptimizer over the same test cases we use to test the port. We will validate that the outputs of the original implementation match the port.

> please try to distill a concrete empirical evaluation plan

Our evaluation plan is to (1) compare the performance of SmoothE with greedy extraction inside an RTL superoptimizer, (2) compare the performance of our SmoothE port with the performance of the original implementation. For both evaluations, we will use test cases written in Verilog. The cost functions we will be using are already written and tested using the greedy extraction method.

> What metrics will you use to assess the SmoothE port on its own, if any? (Or maybe you're not planning on measuring this separately?)

Given that we will be porting the implementation of the SmoothE algorithm from one language to another, we do think it is worthwhile to see whether there is a performance improvement (or drop) between the original implementation and ours. We will run original SmoothE on the same test cases as our SmoothE port to validate (1) that the output is the same and (2) compare the performance in terms of Extraction running time.

> What metrics will you use to assess the changes to the RTL synthesis tool? (Extraction running time? Any metrics of synthesized circuit quality?)

For evaluating synthesized circuit quality, we will use LUT count as our metric. We will also compare the extraction running time. 

> What baseline will you use for the RTL synthesis measurement? (Is it the original tool, using egg's greedy extraction?)

We plan to use the original tool, which is currently using egg’s greedy extraction, as the baseline for the RTL synthesis measurement.

author_association: CONTRIBUTOR
user: login: sampsyo
created_at: 2025-04-11T12:01:02Z
body: OK, sounds good! Thanks for nailing down the plan. I can now approve this proposal.
author_association: OWNER

Diff:
diff --git a/content/blog/2025-5-13-superopt/canonical-example-after.svg b/content/blog/2025-5-13-superopt/canonical-example-after.svg
new file mode 100644
index 000000000..02be1bb84
--- /dev/null
+++ b/content/blog/2025-5-13-superopt/canonical-example-after.svg
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 12.2.1 (0)
+ -->
+<!-- Pages: 1 -->
+<svg width="187pt" height="230pt"
+ viewBox="0.00 0.00 187.00 230.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 226)">
+<polygon fill="white" stroke="none" points="-4,4 -4,-226 183,-226 183,4 -4,4"/>
+<g id="clust1" class="cluster">
+<title>outer_cluster_0</title>
+</g>
+<g id="clust2" class="cluster">
+<title>cluster_0</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M23,-11C23,-11 59,-11 59,-11 65,-11 71,-17 71,-23 71,-23 71,-41 71,-41 71,-47 65,-53 59,-53 59,-53 23,-53 23,-53 17,-53 11,-47 11,-41 11,-41 11,-23 11,-23 11,-17 17,-11 23,-11"/>
+</g>
+<g id="clust4" class="cluster">
+<title>outer_cluster_2</title>
+</g>
+<g id="clust5" class="cluster">
+<title>cluster_2</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M54,-90C54,-90 90,-90 90,-90 96,-90 102,-96 102,-102 102,-102 102,-120 102,-120 102,-126 96,-132 90,-132 90,-132 54,-132 54,-132 48,-132 42,-126 42,-120 42,-120 42,-102 42,-102 42,-96 48,-90 54,-90"/>
+</g>
+<g id="clust7" class="cluster">
+<title>outer_cluster_5</title>
+</g>
+<g id="clust8" class="cluster">
+<title>cluster_5</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M39,-169C39,-169 133,-169 133,-169 139,-169 145,-175 145,-181 145,-181 145,-199 145,-199 145,-205 139,-211 133,-211 133,-211 39,-211 39,-211 33,-211 27,-205 27,-199 27,-199 27,-181 27,-181 27,-175 33,-169 39,-169"/>
+</g>
+<g id="clust10" class="cluster">
+<title>outer_cluster_4</title>
+</g>
+<g id="clust11" class="cluster">
+<title>cluster_4</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M120,-90C120,-90 156,-90 156,-90 162,-90 168,-96 168,-102 168,-102 168,-120 168,-120 168,-126 162,-132 156,-132 156,-132 120,-132 120,-132 114,-132 108,-126 108,-120 108,-120 108,-102 108,-102 108,-96 114,-90 120,-90"/>
+</g>
+<g id="clust13" class="cluster">
+<title>outer_cluster_1</title>
+</g>
+<g id="clust14" class="cluster">
+<title>cluster_1</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M105,-11C105,-11 141,-11 141,-11 147,-11 153,-17 153,-23 153,-23 153,-41 153,-41 153,-47 147,-53 141,-53 141,-53 105,-53 105,-53 99,-53 93,-47 93,-41 93,-41 93,-23 93,-23 93,-17 99,-11 105,-11"/>
+</g>
+<!-- 2.0&#45;&gt;0.0 -->
+<g id="edge1" class="edge">
+<title>2.0:s&#45;&gt;0.0</title>
+<path fill="none" stroke="black" d="M64.5,-95C64.5,-81.37 59.48,-67.09 54.07,-55.68"/>
+<polygon fill="black" stroke="black" points="57.36,-57.38 53.09,-54.25 54.48,-59.36 57.36,-57.38"/>
+</g>
+<!-- 2.0&#45;&gt;1.0 -->
+<g id="edge2" class="edge">
+<title>2.0:s&#45;&gt;1.0</title>
+<path fill="none" stroke="black" d="M79.5,-95C79.5,-79.58 88.63,-65.28 98.52,-54.31"/>
+<polygon fill="black" stroke="black" points="96.52,-58.9 98.73,-54.09 94,-56.48 96.52,-58.9"/>
+</g>
+<!-- 5.0&#45;&gt;0.0 -->
+<g id="edge3" class="edge">
+<title>5.0:s&#45;&gt;0.0</title>
+<path fill="none" stroke="black" d="M107.5,-174C107.5,-139.74 58.03,-164.73 41,-135 27.14,-110.81 30.33,-77.79 34.84,-55.95"/>
+<polygon fill="black" stroke="black" points="35.06,-59.65 35.56,-54.37 31.88,-58.18 35.06,-59.65"/>
+</g>
+<!-- 5.0&#45;&gt;4.0 -->
+<g id="edge4" class="edge">
+<title>5.0:s&#45;&gt;4.0</title>
+<path fill="none" stroke="black" d="M122.5,-174C122.5,-160.8 125.85,-146.48 129.43,-134.93"/>
+<polygon fill="black" stroke="black" points="129.99,-138.73 129.94,-133.43 126.67,-137.6 129.99,-138.73"/>
+</g>
+<!-- 4.0&#45;&gt;0.0 -->
+<g id="edge8" class="edge">
+<title>4.0:s&#45;&gt;0.0</title>
+<path fill="none" stroke="black" d="M145.5,-95C145.5,-86.51 104.18,-64.18 73.5,-48.78"/>
+<polygon fill="black" stroke="black" points="77.32,-49.35 72.23,-47.86 75.28,-52.2 77.32,-49.35"/>
+</g>
+<!-- 4.0&#45;&gt;1.0 -->
+<g id="edge7" class="edge">
+<title>4.0:s&#45;&gt;1.0</title>
+<path fill="none" stroke="black" d="M130.5,-95C130.5,-82.01 128.86,-67.6 127.11,-55.94"/>
+<polygon fill="black" stroke="black" points="129.84,-58.64 126.61,-54.44 126.52,-59.73 129.84,-58.64"/>
+</g>
+<!-- 5.1&#45;&gt;0.0 -->
+<g id="edge6" class="edge">
+<title>5.1:s&#45;&gt;0.0</title>
+<path fill="none" stroke="black" d="M64.5,-174C64.5,-150.86 38.2,-156.64 30,-135 20.22,-109.19 26.31,-77.25 32.64,-56.06"/>
+<polygon fill="black" stroke="black" points="32.57,-59.43 33.78,-54.28 29.62,-57.55 32.57,-59.43"/>
+</g>
+<!-- 5.1&#45;&gt;2.0 -->
+<g id="edge5" class="edge">
+<title>5.1:s&#45;&gt;2.0</title>
+<path fill="none" stroke="black" d="M49.5,-174C49.5,-160.35 54.38,-145.97 59.59,-134.49"/>
+<polygon fill="black" stroke="black" points="59.05,-138.35 60.46,-133.24 56.17,-136.35 59.05,-138.35"/>
+</g>
+<!-- 0.0 -->
+<g id="node1" class="node">
+<title>0.0</title>
+<g id="a_node1"><a xlink:title="0: 0.0">
+<path fill="white" stroke="none" d="M35.67,-16C35.67,-16 46.33,-16 46.33,-16 51.67,-16 57,-21.33 57,-26.67 57,-26.67 57,-37.33 57,-37.33 57,-42.67 51.67,-48 46.33,-48 46.33,-48 35.67,-48 35.67,-48 30.33,-48 25,-42.67 25,-37.33 25,-37.33 25,-26.67 25,-26.67 25,-21.33 30.33,-16 35.67,-16"/>
+<text text-anchor="start" x="37.25" y="-26.2" font-family="Helvetica,sans-Serif" font-size="14.00">2</text>
+<path fill="none" stroke="black" d="M35.67,-16C35.67,-16 46.33,-16 46.33,-16 51.67,-16 57,-21.33 57,-26.67 57,-26.67 57,-37.33 57,-37.33 57,-42.67 51.67,-48 46.33,-48 46.33,-48 35.67,-48 35.67,-48 30.33,-48 25,-42.67 25,-37.33 25,-37.33 25,-26.67 25,-26.67 25,-21.33 30.33,-16 35.67,-16"/>
+</a>
+</g>
+</g>
+<!-- 2.0 -->
+<g id="node2" class="node">
+<title>2.0</title>
+<g id="a_node2"><a xlink:title="2: 2.0">
+<path fill="white" stroke="none" d="M66.67,-95C66.67,-95 77.33,-95 77.33,-95 82.67,-95 88,-100.33 88,-105.67 88,-105.67 88,-116.33 88,-116.33 88,-121.67 82.67,-127 77.33,-127 77.33,-127 66.67,-127 66.67,-127 61.33,-127 56,-121.67 56,-116.33 56,-116.33 56,-105.67 56,-105.67 56,-100.33 61.33,-95 66.67,-95"/>
+<text text-anchor="start" x="69.38" y="-105.2" font-family="Helvetica,sans-Serif" font-size="14.00">*</text>
+<path fill="none" stroke="black" d="M66.67,-95C66.67,-95 77.33,-95 77.33,-95 82.67,-95 88,-100.33 88,-105.67 88,-105.67 88,-116.33 88,-116.33 88,-121.67 82.67,-127 77.33,-127 77.33,-127 66.67,-127 66.67,-127 61.33,-127 56,-121.67 56,-116.33 56,-116.33 56,-105.67 56,-105.67 56,-100.33 61.33,-95 66.67,-95"/>
+</a>
+</g>
+</g>
+<!-- 1.0 -->
+<g id="node3" class="node">
+<title>1.0</title>
+<g id="a_node3"><a xlink:title="1: 1.0">
+<path fill="white" stroke="none" d="M117.67,-16C117.67,-16 128.33,-16 128.33,-16 133.67,-16 139,-21.33 139,-26.67 139,-26.67 139,-37.33 139,-37.33 139,-42.67 133.67,-48 128.33,-48 128.33,-48 117.67,-48 117.67,-48 112.33,-48 107,-42.67 107,-37.33 107,-37.33 107,-26.67 107,-26.67 107,-21.33 112.33,-16 117.67,-16"/>
+<text text-anchor="start" x="119.25" y="-26.2" font-family="Helvetica,sans-Serif" font-size="14.00">a</text>
+<path fill="none" stroke="black" d="M117.67,-16C117.67,-16 128.33,-16 128.33,-16 133.67,-16 139,-21.33 139,-26.67 139,-26.67 139,-37.33 139,-37.33 139,-42.67 133.67,-48 128.33,-48 128.33,-48 117.67,-48 117.67,-48 112.33,-48 107,-42.67 107,-37.33 107,-37.33 107,-26.67 107,-26.67 107,-21.33 112.33,-16 117.67,-16"/>
+</a>
+</g>
+</g>
+<!-- 5.0 -->
+<g id="node4" class="node">
+<title>5.0</title>
+<g id="a_node4"><a xlink:title="5: 5.0">
+<path fill="white" stroke="none" d="M109.67,-174C109.67,-174 120.33,-174 120.33,-174 125.67,-174 131,-179.33 131,-184.67 131,-184.67 131,-195.33 131,-195.33 131,-200.67 125.67,-206 120.33,-206 120.33,-206 109.67,-206 109.67,-206 104.33,-206 99,-200.67 99,-195.33 99,-195.33 99,-184.67 99,-184.67 99,-179.33 104.33,-174 109.67,-174"/>
+<text text-anchor="start" x="112.38" y="-184.2" font-family="Helvetica,sans-Serif" font-size="14.00">*</text>
+<path fill="none" stroke="black" d="M109.67,-174C109.67,-174 120.33,-174 120.33,-174 125.67,-174 131,-179.33 131,-184.67 131,-184.67 131,-195.33 131,-195.33 131,-200.67 125.67,-206 120.33,-206 120.33,-206 109.67,-206 109.67,-206 104.33,-206 99,-200.67 99,-195.33 99,-195.33 99,-184.67 99,-184.67 99,-179.33 104.33,-174 109.67,-174"/>
+</a>
+</g>
+</g>
+<!-- 4.0 -->
+<g id="node5" class="node">
+<title>4.0</title>
+<g id="a_node5"><a xlink:title="4: 4.0">
+<path fill="white" stroke="none" d="M132.67,-95C132.67,-95 143.33,-95 143.33,-95 148.67,-95 154,-100.33 154,-105.67 154,-105.67 154,-116.33 154,-116.33 154,-121.67 148.67,-127 143.33,-127 143.33,-127 132.67,-127 132.67,-127 127.33,-127 122,-121.67 122,-116.33 122,-116.33 122,-105.67 122,-105.67 122,-100.33 127.33,-95 132.67,-95"/>
+<text text-anchor="start" x="136.12" y="-105.2" font-family="Helvetica,sans-Serif" font-size="14.00">/</text>
+<path fill="none" stroke="black" d="M132.67,-95C132.67,-95 143.33,-95 143.33,-95 148.67,-95 154,-100.33 154,-105.67 154,-105.67 154,-116.33 154,-116.33 154,-121.67 148.67,-127 143.33,-127 143.33,-127 132.67,-127 132.67,-127 127.33,-127 122,-121.67 122,-116.33 122,-116.33 122,-105.67 122,-105.67 122,-100.33 127.33,-95 132.67,-95"/>
+</a>
+</g>
+</g>
+<!-- 5.1 -->
+<g id="node6" class="node">
+<title>5.1</title>
+<g id="a_node6"><a xlink:title="5: 5.1">
+<path fill="white" stroke="none" d="M51.67,-174C51.67,-174 62.33,-174 62.33,-174 67.67,-174 73,-179.33 73,-184.67 73,-184.67 73,-195.33 73,-195.33 73,-200.67 67.67,-206 62.33,-206 62.33,-206 51.67,-206 51.67,-206 46.33,-206 41,-200.67 41,-195.33 41,-195.33 41,-184.67 41,-184.67 41,-179.33 46.33,-174 51.67,-174"/>
+<text text-anchor="start" x="55.12" y="-184.2" font-family="Helvetica,sans-Serif" font-size="14.00">/</text>
+<path fill="none" stroke="black" d="M51.67,-174C51.67,-174 62.33,-174 62.33,-174 67.67,-174 73,-179.33 73,-184.67 73,-184.67 73,-195.33 73,-195.33 73,-200.67 67.67,-206 62.33,-206 62.33,-206 51.67,-206 51.67,-206 46.33,-206 41,-200.67 41,-195.33 41,-195.33 41,-184.67 41,-184.67 41,-179.33 46.33,-174 51.67,-174"/>
+</a>
+</g>
+</g>
+</g>
+</svg>
diff --git a/content/blog/2025-5-13-superopt/canonical-example-before.svg b/content/blog/2025-5-13-superopt/canonical-example-before.svg
new file mode 100644
index 000000000..6be661ac1
--- /dev/null
+++ b/content/blog/2025-5-13-superopt/canonical-example-before.svg
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 12.2.1 (0)
+ -->
+<!-- Pages: 1 -->
+<svg width="156pt" height="230pt"
+ viewBox="0.00 0.00 156.00 230.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 226)">
+<polygon fill="white" stroke="none" points="-4,4 -4,-226 152,-226 152,4 -4,4"/>
+<g id="clust1" class="cluster">
+<title>outer_cluster_1</title>
+</g>
+<g id="clust2" class="cluster">
+<title>cluster_1</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M23,-11C23,-11 59,-11 59,-11 65,-11 71,-17 71,-23 71,-23 71,-41 71,-41 71,-47 65,-53 59,-53 59,-53 23,-53 23,-53 17,-53 11,-47 11,-41 11,-41 11,-23 11,-23 11,-17 17,-11 23,-11"/>
+</g>
+<g id="clust4" class="cluster">
+<title>outer_cluster_3</title>
+</g>
+<g id="clust5" class="cluster">
+<title>cluster_3</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M69,-169C69,-169 105,-169 105,-169 111,-169 117,-175 117,-181 117,-181 117,-199 117,-199 117,-205 111,-211 105,-211 105,-211 69,-211 69,-211 63,-211 57,-205 57,-199 57,-199 57,-181 57,-181 57,-175 63,-169 69,-169"/>
+</g>
+<g id="clust7" class="cluster">
+<title>outer_cluster_0</title>
+</g>
+<g id="clust8" class="cluster">
+<title>cluster_0</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M89,-11C89,-11 125,-11 125,-11 131,-11 137,-17 137,-23 137,-23 137,-41 137,-41 137,-47 131,-53 125,-53 125,-53 89,-53 89,-53 83,-53 77,-47 77,-41 77,-41 77,-23 77,-23 77,-17 83,-11 89,-11"/>
+</g>
+<g id="clust10" class="cluster">
+<title>outer_cluster_2</title>
+</g>
+<g id="clust11" class="cluster">
+<title>cluster_2</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M50,-90C50,-90 86,-90 86,-90 92,-90 98,-96 98,-102 98,-102 98,-120 98,-120 98,-126 92,-132 86,-132 86,-132 50,-132 50,-132 44,-132 38,-126 38,-120 38,-120 38,-102 38,-102 38,-96 44,-90 50,-90"/>
+</g>
+<!-- 3.0&#45;&gt;2.0 -->
+<g id="edge1" class="edge">
+<title>3.0:s&#45;&gt;2.0</title>
+<path fill="none" stroke="black" d="M79.5,-174C79.5,-160.98 77.02,-146.67 74.36,-135.08"/>
+<polygon fill="black" stroke="black" points="77.28,-137.11 73.53,-133.36 74.12,-138.63 77.28,-137.11"/>
+</g>
+<!-- 3.0&#45;&gt;0.0 -->
+<g id="edge2" class="edge">
+<title>3.0:s&#45;&gt;0.0</title>
+<path fill="none" stroke="black" d="M94.5,-174C94.5,-156.55 97.32,-152.37 99,-135 101.61,-108.04 103.95,-77 105.42,-56.32"/>
+<polygon fill="black" stroke="black" points="106.73,-59.69 105.66,-54.5 103.26,-59.22 106.73,-59.69"/>
+</g>
+<!-- 2.0&#45;&gt;1.0 -->
+<g id="edge4" class="edge">
+<title>2.0:s&#45;&gt;1.0</title>
+<path fill="none" stroke="black" d="M75.5,-95C75.5,-80.37 68.07,-65.96 60.11,-54.73"/>
+<polygon fill="black" stroke="black" points="64.22,-56.46 59.49,-54.09 61.71,-58.9 64.22,-56.46"/>
+</g>
+<!-- 2.0&#45;&gt;0.0 -->
+<g id="edge3" class="edge">
+<title>2.0:s&#45;&gt;0.0</title>
+<path fill="none" stroke="black" d="M60.5,-95C60.5,-79.34 70.11,-65.11 80.59,-54.24"/>
+<polygon fill="black" stroke="black" points="78.17,-58.47 80.94,-53.96 75.96,-55.76 78.17,-58.47"/>
+</g>
+<!-- 1.0 -->
+<g id="node1" class="node">
+<title>1.0</title>
+<g id="a_node1"><a xlink:title="1: 1.0">
+<path fill="white" stroke="none" d="M35.67,-16C35.67,-16 46.33,-16 46.33,-16 51.67,-16 57,-21.33 57,-26.67 57,-26.67 57,-37.33 57,-37.33 57,-42.67 51.67,-48 46.33,-48 46.33,-48 35.67,-48 35.67,-48 30.33,-48 25,-42.67 25,-37.33 25,-37.33 25,-26.67 25,-26.67 25,-21.33 30.33,-16 35.67,-16"/>
+<text text-anchor="start" x="37.25" y="-26.2" font-family="Helvetica,sans-Serif" font-size="14.00">a</text>
+<path fill="none" stroke="black" d="M35.67,-16C35.67,-16 46.33,-16 46.33,-16 51.67,-16 57,-21.33 57,-26.67 57,-26.67 57,-37.33 57,-37.33 57,-42.67 51.67,-48 46.33,-48 46.33,-48 35.67,-48 35.67,-48 30.33,-48 25,-42.67 25,-37.33 25,-37.33 25,-26.67 25,-26.67 25,-21.33 30.33,-16 35.67,-16"/>
+</a>
+</g>
+</g>
+<!-- 3.0 -->
+<g id="node2" class="node">
+<title>3.0</title>
+<g id="a_node2"><a xlink:title="3: 3.0">
+<path fill="white" stroke="none" d="M81.67,-174C81.67,-174 92.33,-174 92.33,-174 97.67,-174 103,-179.33 103,-184.67 103,-184.67 103,-195.33 103,-195.33 103,-200.67 97.67,-206 92.33,-206 92.33,-206 81.67,-206 81.67,-206 76.33,-206 71,-200.67 71,-195.33 71,-195.33 71,-184.67 71,-184.67 71,-179.33 76.33,-174 81.67,-174"/>
+<text text-anchor="start" x="85.12" y="-184.2" font-family="Helvetica,sans-Serif" font-size="14.00">/</text>
+<path fill="none" stroke="black" d="M81.67,-174C81.67,-174 92.33,-174 92.33,-174 97.67,-174 103,-179.33 103,-184.67 103,-184.67 103,-195.33 103,-195.33 103,-200.67 97.67,-206 92.33,-206 92.33,-206 81.67,-206 81.67,-206 76.33,-206 71,-200.67 71,-195.33 71,-195.33 71,-184.67 71,-184.67 71,-179.33 76.33,-174 81.67,-174"/>
+</a>
+</g>
+</g>
+<!-- 2.0 -->
+<g id="node3" class="node">
+<title>2.0</title>
+<g id="a_node3"><a xlink:title="2: 2.0">
+<path fill="white" stroke="none" d="M62.67,-95C62.67,-95 73.33,-95 73.33,-95 78.67,-95 84,-100.33 84,-105.67 84,-105.67 84,-116.33 84,-116.33 84,-121.67 78.67,-127 73.33,-127 73.33,-127 62.67,-127 62.67,-127 57.33,-127 52,-121.67 52,-116.33 52,-116.33 52,-105.67 52,-105.67 52,-100.33 57.33,-95 62.67,-95"/>
+<text text-anchor="start" x="65.38" y="-105.2" font-family="Helvetica,sans-Serif" font-size="14.00">*</text>
+<path fill="none" stroke="black" d="M62.67,-95C62.67,-95 73.33,-95 73.33,-95 78.67,-95 84,-100.33 84,-105.67 84,-105.67 84,-116.33 84,-116.33 84,-121.67 78.67,-127 73.33,-127 73.33,-127 62.67,-127 62.67,-127 57.33,-127 52,-121.67 52,-116.33 52,-116.33 52,-105.67 52,-105.67 52,-100.33 57.33,-95 62.67,-95"/>
+</a>
+</g>
+</g>
+<!-- 0.0 -->
+<g id="node4" class="node">
+<title>0.0</title>
+<g id="a_node4"><a xlink:title="0: 0.0">
+<path fill="white" stroke="none" d="M101.67,-16C101.67,-16 112.33,-16 112.33,-16 117.67,-16 123,-21.33 123,-26.67 123,-26.67 123,-37.33 123,-37.33 123,-42.67 117.67,-48 112.33,-48 112.33,-48 101.67,-48 101.67,-48 96.33,-48 91,-42.67 91,-37.33 91,-37.33 91,-26.67 91,-26.67 91,-21.33 96.33,-16 101.67,-16"/>
+<text text-anchor="start" x="103.25" y="-26.2" font-family="Helvetica,sans-Serif" font-size="14.00">2</text>
+<path fill="none" stroke="black" d="M101.67,-16C101.67,-16 112.33,-16 112.33,-16 117.67,-16 123,-21.33 123,-26.67 123,-26.67 123,-37.33 123,-37.33 123,-42.67 117.67,-48 112.33,-48 112.33,-48 101.67,-48 101.67,-48 96.33,-48 91,-42.67 91,-37.33 91,-37.33 91,-26.67 91,-26.67 91,-21.33 96.33,-16 101.67,-16"/>
+</a>
+</g>
+</g>
+</g>
+</svg>
diff --git a/content/blog/2025-5-13-superopt/canonical-example.svg b/content/blog/2025-5-13-superopt/canonical-example.svg
new file mode 100644
index 000000000..6da73463a
--- /dev/null
+++ b/content/blog/2025-5-13-superopt/canonical-example.svg
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 12.2.1 (0)
+ -->
+<!-- Pages: 1 -->
+<svg width="225pt" height="230pt"
+ viewBox="0.00 0.00 225.00 230.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 226)">
+<polygon fill="white" stroke="none" points="-4,4 -4,-226 221,-226 221,4 -4,4"/>
+<g id="clust1" class="cluster">
+<title>outer_cluster_2</title>
+</g>
+<g id="clust2" class="cluster">
+<title>cluster_2</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M35,-90C35,-90 187,-90 187,-90 193,-90 199,-96 199,-102 199,-102 199,-120 199,-120 199,-126 193,-132 187,-132 187,-132 35,-132 35,-132 29,-132 23,-126 23,-120 23,-120 23,-102 23,-102 23,-96 29,-90 35,-90"/>
+</g>
+<g id="clust4" class="cluster">
+<title>outer_cluster_0</title>
+</g>
+<g id="clust5" class="cluster">
+<title>cluster_0</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M23,-11C23,-11 59,-11 59,-11 65,-11 71,-17 71,-23 71,-23 71,-41 71,-41 71,-47 65,-53 59,-53 59,-53 23,-53 23,-53 17,-53 11,-47 11,-41 11,-41 11,-23 11,-23 11,-17 17,-11 23,-11"/>
+</g>
+<g id="clust7" class="cluster">
+<title>outer_cluster_3</title>
+</g>
+<g id="clust8" class="cluster">
+<title>cluster_3</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M26,-169C26,-169 62,-169 62,-169 68,-169 74,-175 74,-181 74,-181 74,-199 74,-199 74,-205 68,-211 62,-211 62,-211 26,-211 26,-211 20,-211 14,-205 14,-199 14,-199 14,-181 14,-181 14,-175 20,-169 26,-169"/>
+</g>
+<g id="clust10" class="cluster">
+<title>outer_cluster_1</title>
+</g>
+<g id="clust11" class="cluster">
+<title>cluster_1</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M89,-11C89,-11 125,-11 125,-11 131,-11 137,-17 137,-23 137,-23 137,-41 137,-41 137,-47 131,-53 125,-53 125,-53 89,-53 89,-53 83,-53 77,-47 77,-41 77,-41 77,-23 77,-23 77,-17 83,-11 89,-11"/>
+</g>
+<g id="clust13" class="cluster">
+<title>outer_cluster_5</title>
+</g>
+<g id="clust14" class="cluster">
+<title>cluster_5</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M158,-11C158,-11 194,-11 194,-11 200,-11 206,-17 206,-23 206,-23 206,-41 206,-41 206,-47 200,-53 194,-53 194,-53 158,-53 158,-53 152,-53 146,-47 146,-41 146,-41 146,-23 146,-23 146,-17 152,-11 158,-11"/>
+</g>
+<!-- 2.0&#45;&gt;0.0 -->
+<g id="edge1" class="edge">
+<title>2.0:s&#45;&gt;0.0</title>
+<path fill="none" stroke="black" d="M45.5,-95C45.5,-82.07 44.51,-67.66 43.47,-55.99"/>
+<polygon fill="black" stroke="black" points="45.85,-59.06 43.17,-54.49 42.41,-59.73 45.85,-59.06"/>
+</g>
+<!-- 2.0&#45;&gt;1.0 -->
+<g id="edge2" class="edge">
+<title>2.0:s&#45;&gt;1.0</title>
+<path fill="none" stroke="black" d="M60.5,-95C60.5,-79.34 70.11,-65.11 80.59,-54.24"/>
+<polygon fill="black" stroke="black" points="78.17,-58.47 80.94,-53.96 75.96,-55.76 78.17,-58.47"/>
+</g>
+<!-- 2.1&#45;&gt;0.0 -->
+<g id="edge4" class="edge">
+<title>2.1:s&#45;&gt;0.0</title>
+<path fill="none" stroke="black" d="M118.5,-95C118.5,-88.62 92.55,-68.87 70.69,-53.35"/>
+<polygon fill="black" stroke="black" points="76.26,-53.2 70.97,-53.44 75.26,-56.55 76.26,-53.2"/>
+</g>
+<!-- 2.1&#45;&gt;1.0 -->
+<g id="edge3" class="edge">
+<title>2.1:s&#45;&gt;1.0</title>
+<path fill="none" stroke="black" d="M103.5,-95C103.5,-82.08 104.27,-67.68 105.08,-56"/>
+<polygon fill="black" stroke="black" points="106.29,-59.7 105.31,-54.5 102.83,-59.18 106.29,-59.7"/>
+</g>
+<!-- 2.2&#45;&gt;1.0 -->
+<g id="edge5" class="edge">
+<title>2.2:s&#45;&gt;1.0</title>
+<path fill="none" stroke="black" d="M161.5,-95C161.5,-78.68 150.71,-64.61 138.74,-54.02"/>
+<polygon fill="black" stroke="black" points="142.57,-55.8 137.98,-53.14 139.91,-58.07 142.57,-55.8"/>
+</g>
+<!-- 2.2&#45;&gt;5.0 -->
+<g id="edge6" class="edge">
+<title>2.2:s&#45;&gt;5.0</title>
+<path fill="none" stroke="black" d="M176.5,-95C176.5,-82.22 176.39,-67.96 176.28,-56.35"/>
+<polygon fill="black" stroke="black" points="178.09,-59.48 176.24,-54.51 174.59,-59.55 178.09,-59.48"/>
+</g>
+<!-- 3.0&#45;&gt;2.0 -->
+<g id="edge7" class="edge">
+<title>3.0:s&#45;&gt;2.0</title>
+<path fill="none" stroke="black" d="M36.5,-174C36.5,-160.75 40.06,-146.42 43.88,-134.88"/>
+<polygon fill="black" stroke="black" points="44.27,-138.7 44.45,-133.41 41.01,-137.43 44.27,-138.7"/>
+</g>
+<!-- 3.0&#45;&gt;0.0 -->
+<g id="edge8" class="edge">
+<title>3.0:s&#45;&gt;0.0</title>
+<path fill="none" stroke="black" d="M51.5,-174C51.5,-152.27 28.91,-155.6 22,-135 13.13,-108.58 21.92,-76.83 30.27,-55.85"/>
+<polygon fill="black" stroke="black" points="30.34,-59.6 31.03,-54.35 27.21,-58.03 30.34,-59.6"/>
+</g>
+<!-- 2.0 -->
+<g id="node1" class="node">
+<title>2.0</title>
+<g id="a_node1"><a xlink:title="2: 2.0">
+<path fill="white" stroke="none" d="M47.67,-95C47.67,-95 58.33,-95 58.33,-95 63.67,-95 69,-100.33 69,-105.67 69,-105.67 69,-116.33 69,-116.33 69,-121.67 63.67,-127 58.33,-127 58.33,-127 47.67,-127 47.67,-127 42.33,-127 37,-121.67 37,-116.33 37,-116.33 37,-105.67 37,-105.67 37,-100.33 42.33,-95 47.67,-95"/>
+<text text-anchor="start" x="50.38" y="-105.2" font-family="Helvetica,sans-Serif" font-size="14.00">*</text>
+<path fill="none" stroke="black" d="M47.67,-95C47.67,-95 58.33,-95 58.33,-95 63.67,-95 69,-100.33 69,-105.67 69,-105.67 69,-116.33 69,-116.33 69,-121.67 63.67,-127 58.33,-127 58.33,-127 47.67,-127 47.67,-127 42.33,-127 37,-121.67 37,-116.33 37,-116.33 37,-105.67 37,-105.67 37,-100.33 42.33,-95 47.67,-95"/>
+</a>
+</g>
+</g>
+<!-- 0.0 -->
+<g id="node2" class="node">
+<title>0.0</title>
+<g id="a_node2"><a xlink:title="0: 0.0">
+<path fill="white" stroke="none" d="M35.67,-16C35.67,-16 46.33,-16 46.33,-16 51.67,-16 57,-21.33 57,-26.67 57,-26.67 57,-37.33 57,-37.33 57,-42.67 51.67,-48 46.33,-48 46.33,-48 35.67,-48 35.67,-48 30.33,-48 25,-42.67 25,-37.33 25,-37.33 25,-26.67 25,-26.67 25,-21.33 30.33,-16 35.67,-16"/>
+<text text-anchor="start" x="37.25" y="-26.2" font-family="Helvetica,sans-Serif" font-size="14.00">2</text>
+<path fill="none" stroke="black" d="M35.67,-16C35.67,-16 46.33,-16 46.33,-16 51.67,-16 57,-21.33 57,-26.67 57,-26.67 57,-37.33 57,-37.33 57,-42.67 51.67,-48 46.33,-48 46.33,-48 35.67,-48 35.67,-48 30.33,-48 25,-42.67 25,-37.33 25,-37.33 25,-26.67 25,-26.67 25,-21.33 30.33,-16 35.67,-16"/>
+</a>
+</g>
+</g>
+<!-- 1.0 -->
+<g id="node3" class="node">
+<title>1.0</title>
+<g id="a_node3"><a xlink:title="1: 1.0">
+<path fill="white" stroke="none" d="M101.67,-16C101.67,-16 112.33,-16 112.33,-16 117.67,-16 123,-21.33 123,-26.67 123,-26.67 123,-37.33 123,-37.33 123,-42.67 117.67,-48 112.33,-48 112.33,-48 101.67,-48 101.67,-48 96.33,-48 91,-42.67 91,-37.33 91,-37.33 91,-26.67 91,-26.67 91,-21.33 96.33,-16 101.67,-16"/>
+<text text-anchor="start" x="103.25" y="-26.2" font-family="Helvetica,sans-Serif" font-size="14.00">a</text>
+<path fill="none" stroke="black" d="M101.67,-16C101.67,-16 112.33,-16 112.33,-16 117.67,-16 123,-21.33 123,-26.67 123,-26.67 123,-37.33 123,-37.33 123,-42.67 117.67,-48 112.33,-48 112.33,-48 101.67,-48 101.67,-48 96.33,-48 91,-42.67 91,-37.33 91,-37.33 91,-26.67 91,-26.67 91,-21.33 96.33,-16 101.67,-16"/>
+</a>
+</g>
+</g>
+<!-- 2.1 -->
+<g id="node4" class="node">
+<title>2.1</title>
+<g id="a_node4"><a xlink:title="2: 2.1">
+<path fill="white" stroke="none" d="M105.67,-95C105.67,-95 116.33,-95 116.33,-95 121.67,-95 127,-100.33 127,-105.67 127,-105.67 127,-116.33 127,-116.33 127,-121.67 121.67,-127 116.33,-127 116.33,-127 105.67,-127 105.67,-127 100.33,-127 95,-121.67 95,-116.33 95,-116.33 95,-105.67 95,-105.67 95,-100.33 100.33,-95 105.67,-95"/>
+<text text-anchor="start" x="108.38" y="-105.2" font-family="Helvetica,sans-Serif" font-size="14.00">*</text>
+<path fill="none" stroke="black" d="M105.67,-95C105.67,-95 116.33,-95 116.33,-95 121.67,-95 127,-100.33 127,-105.67 127,-105.67 127,-116.33 127,-116.33 127,-121.67 121.67,-127 116.33,-127 116.33,-127 105.67,-127 105.67,-127 100.33,-127 95,-121.67 95,-116.33 95,-116.33 95,-105.67 95,-105.67 95,-100.33 100.33,-95 105.67,-95"/>
+</a>
+</g>
+</g>
+<!-- 2.2 -->
+<g id="node5" class="node">
+<title>2.2</title>
+<g id="a_node5"><a xlink:title="2: 2.2">
+<path fill="white" stroke="none" d="M163.67,-95C163.67,-95 174.33,-95 174.33,-95 179.67,-95 185,-100.33 185,-105.67 185,-105.67 185,-116.33 185,-116.33 185,-121.67 179.67,-127 174.33,-127 174.33,-127 163.67,-127 163.67,-127 158.33,-127 153,-121.67 153,-116.33 153,-116.33 153,-105.67 153,-105.67 153,-100.33 158.33,-95 163.67,-95"/>
+<text text-anchor="start" x="160.75" y="-105.2" font-family="Helvetica,sans-Serif" font-size="14.00">&lt;&lt;</text>
+<path fill="none" stroke="black" d="M163.67,-95C163.67,-95 174.33,-95 174.33,-95 179.67,-95 185,-100.33 185,-105.67 185,-105.67 185,-116.33 185,-116.33 185,-121.67 179.67,-127 174.33,-127 174.33,-127 163.67,-127 163.67,-127 158.33,-127 153,-121.67 153,-116.33 153,-116.33 153,-105.67 153,-105.67 153,-100.33 158.33,-95 163.67,-95"/>
+</a>
+</g>
+</g>
+<!-- 5.0 -->
+<g id="node6" class="node">
+<title>5.0</title>
+<g id="a_node6"><a xlink:title="5: 5.0">
+<path fill="white" stroke="none" d="M170.67,-16C170.67,-16 181.33,-16 181.33,-16 186.67,-16 192,-21.33 192,-26.67 192,-26.67 192,-37.33 192,-37.33 192,-42.67 186.67,-48 181.33,-48 181.33,-48 170.67,-48 170.67,-48 165.33,-48 160,-42.67 160,-37.33 160,-37.33 160,-26.67 160,-26.67 160,-21.33 165.33,-16 170.67,-16"/>
+<text text-anchor="start" x="172.25" y="-26.2" font-family="Helvetica,sans-Serif" font-size="14.00">1</text>
+<path fill="none" stroke="black" d="M170.67,-16C170.67,-16 181.33,-16 181.33,-16 186.67,-16 192,-21.33 192,-26.67 192,-26.67 192,-37.33 192,-37.33 192,-42.67 186.67,-48 181.33,-48 181.33,-48 170.67,-48 170.67,-48 165.33,-48 160,-42.67 160,-37.33 160,-37.33 160,-26.67 160,-26.67 160,-21.33 165.33,-16 170.67,-16"/>
+</a>
+</g>
+</g>
+<!-- 3.0 -->
+<g id="node7" class="node">
+<title>3.0</title>
+<g id="a_node7"><a xlink:title="3: 3.0">
+<path fill="white" stroke="none" d="M38.67,-174C38.67,-174 49.33,-174 49.33,-174 54.67,-174 60,-179.33 60,-184.67 60,-184.67 60,-195.33 60,-195.33 60,-200.67 54.67,-206 49.33,-206 49.33,-206 38.67,-206 38.67,-206 33.33,-206 28,-200.67 28,-195.33 28,-195.33 28,-184.67 28,-184.67 28,-179.33 33.33,-174 38.67,-174"/>
+<text text-anchor="start" x="42.12" y="-184.2" font-family="Helvetica,sans-Serif" font-size="14.00">/</text>
+<path fill="none" stroke="black" d="M38.67,-174C38.67,-174 49.33,-174 49.33,-174 54.67,-174 60,-179.33 60,-184.67 60,-184.67 60,-195.33 60,-195.33 60,-200.67 54.67,-206 49.33,-206 49.33,-206 38.67,-206 38.67,-206 33.33,-206 28,-200.67 28,-195.33 28,-195.33 28,-184.67 28,-184.67 28,-179.33 33.33,-174 38.67,-174"/>
+</a>
+</g>
+</g>
+</g>
+</svg>
diff --git a/content/blog/2025-5-13-superopt/index.md b/content/blog/2025-5-13-superopt/index.md
new file mode 100644
index 000000000..2e9642e36
--- /dev/null
+++ b/content/blog/2025-5-13-superopt/index.md
@@ -0,0 +1,194 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+[Equality-graphs](https://en.wikipedia.org/wiki/E-graph), or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="Example e-graph for a simple arithmetic expression before saturation" width="33%">
+
+In [*equality saturation*](https://arxiv.org/pdf/1012.1802), we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. As long as the rewrites do not lead to unbounded e-graph expansion, the e-graph will reach a saturated state where all possible programs resulting from all rewrite rules are represented within the e-graph.
+
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="Example e-graph for a simple arithmetic expression after saturation." width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently, RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of [technology mapping](https://course.ece.cmu.edu/~ee760/760docs/lec10.pdf) in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area (or number of LUTs), is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs/ASICs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the Verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+<LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes Verilog as input, but converts it into LutLang before performing optimizations and then converts it back into Verilog.
+
+Below we give an example of a half-adder written in LutLang:
+
+`(BUS (AND a b) (XOR a b))`
+
+
+### Equality Saturation
+An e-graph representation of the original design using boolean logic, is shown below:
+
+<img src="simple_2_output_before.svg" alt="" width="20%">
+
+The two-input gates are first transformed into programmable LUTs specified by three parameters: a truth table (numeric e-node), and two operands (a and b). During equality saturation, rewrite rules are applied until all possible designs are encoded in the e-graph.
+
+<img src="simple_2_output_lvv_after.svg" alt="" width="33%">
+
+
+### Design Extraction
+
+During extraction, an optimal design is produced using either a greedy or exact (linear programming) method as explained in the [E-graphs and Equality Saturation](#e-graphs-and-equality-saturation) section.
+To apply linear programming to the e-graph extraction problem, a set of constraints and objective function must be specified.
+We use the mixed integer linear programming problem formulation specified by [Yang et al.](https://arxiv.org/pdf/2101.01332):
+
+Let:
+- `i = 0, ..., N - 1` be the set of e-nodes in the e-graph.
+- `m = 0, ..., M - 1` be the set of e-classes in the e-graph.
+- `e_m` denote the set of e-nodes within e-class `m`: `{i | i ∈ e_m}`.
+We introduce a binary integer variable `x_i` for each e-node `i`. A node `i` is selected if `x_i = 1`, and not selected otherwise.
+#### Objective Function:
+Each e-node is associated with a cost `c_i`. The objective is to minimize the total cost of the selected nodes:
+#### Subject to:
+1. `x_i ∈ {0, 1}` for all `i`.
+2. `Σ x_i = 1` for all `i ∈ e_0` (root e-class).
+3. For all `i ∈ h_i` and `m ∈ h_i`, `x_i ≤ Σ x_j` for all `j ∈ e_m`.
+4. Acyclicity constraints: For all `i, m ∈ h_i`, `t_g(i) - t_m - c + A(1 - x_i) ≥ 0`.
+5. Bounds on Acyclicity variables: `0 ≤ t_m ≤ 1`.
+
+Currently, egg's LP extractor is written to use the [COIN-OR Branch-and-Cut](https://github.com/coin-or/Cbc) (cbc) ILP solver, but there are a number of ILP solvers which have been shown to perform well -- some of which have already been applied to the e-graph extraction problem -- so it is not yet clear whether other solvers perform better the ILP formulation of e-graph extraction. At the same time, an ILP solver must support any possible valid set of constraints, variables, and objective function. Complex, yet-unseen problems -- which will arise frequently when applying e-graphs to domains like code optimization and RTL synthesis -- can trigger [unexpected behaviors](https://github.com/coin-or/Cbc/issues/478) in the solver, leading to errors which are difficult to reason about. As we show in [Results](#results), such errors occur frequently when applying cbc to e-graph-based ASIC logic synthesis.
+
+To sidestep such issues, and enable efficient performance testing of multiple solvers on logic synthesis problems, we chose to use the good\_lp rust crate to implement an LP extractor with multiple solver backends.
+The good\_lp rust crate provides a clean API for expressing problem variables, constraints, and objective function. It also provides multiple solver backends, including [HiGHs](https://highs.dev/), [SCIP](https://scipopt.org/#scipoptsuite), [microlp](https://github.com/Specy/microlp/), and COIN-OR Branch-and-Cut, which can be selected at compile- or run-time.
+good\_lp will transform the programmer-provided problem specification into the implementation-specific data structures and method invocations to solve the problem using the chosen LP solver. By writing our exact extractor using good\_lp, the implementation is agnostic to the solver backend and the problem variables, constraints, and objective function are easy to read and understand in the code.
+
+## Results
+
+### FPGA Synthesis
+
+We first compare the number of LUTs in the designs synthesized using greedy and exact extraction on the [ISCAS85](https://github.com/matth2k/synth-benchmarks/tree/main/verilog/iscas85) design benchmarks. E-graph-based tech mapping is performed after an initial FPGA synthesis using [Yosys](https://yosyshq.readthedocs.io/projects/yosys/en/0.46/cmd/synth_xilinx.html), which does an initial tech mapping using the ABC tool. Since finding an exact solution quickly becomes prohibitive in terms of extraction time (the size of the e-graph and corresponding linear programming problem gets too large) we fix a 2000 node limit on the size of the e-graph and time out the solver after (roughly) 10 minutes.
+
+| Benchmark | Yosys (w/ ABC) | Greedy LUT Count | HiGHS LUT Count | CBC LUT Count | egg CBC LUT Count |
+|-----------|-------|------------------|-----------------|---------------|-------------------|
+| c1355     | 96    | 94               | 96              | 96            | 96                |
+| c17       | 2     | 2                | 2               | 2             | 2                 |
+| c1908     | 86    | 85               | 85              | 85            | 85                |
+| c2670     | 120   | 119              | 120             | 120           | 120               |
+| c3540     | 265   | 260              | 264             | 264           | 264               |
+| c432      | 51    | 50               | 49              | 49            | 49                |
+| c499      | 90    | 90               | 90              | 90            | 90                |
+| c5315     | 267   | 266              | 266             | 267           | 267               |
+| c6288     | 520   | 512              | 520             | 520           | 520               |
+| c7552     | 335   | 325              | 334             | 335           | 335               |
+| c880      | 84    | 81               | 80              | 80            | 80                |
+
+The times to solution (in seconds) are reported in the table below:
+
+| Benchmark | Greedy Time | HiGHS Time | CBC Time | egg CBC Time |
+|-----------|-------------|------------|----------|--------------|
+| c1355     | 0.018       | 59.74      | 598.38   | 7.23         |
+| c17       | 0.00003     | 0.017      | 0.007    | 0.09         |
+| c1908     | 0.017       | 21.28      | 601.29   | 4.17         |
+| c2670     | 0.020       | 8.07       | 0.868    | 0.87         |
+| c3540     | 0.035       | 18.29      | 0.592    | 0.59         |
+| c432      | 0.012       | 41.42      | 602.13   | 101.40       |
+| c499      | 0.016       | 52.84      | 606.19   | 7.21         |
+| c5315     | 0.019       | 12.10      | 0.624    | 0.62         |
+| c6288     | 0.045       | 23.51      | 605.03   | 0.80         |
+| c7552     | 0.027       | 9.62       | 0.425    | 0.42         |
+| c880      | 0.016       | 11.45      | 605.36   | 2.15         |
+
+We observe a scalability-quality tradeoff for exact extraction. Exact extraction requires orders of magnitude longer to produce a solution and very rarely produces better designs than the greedy extractor. This is likely due to the restrictions we place on the size of the e-graph and solver. Without restrictions on running time and e-graph size, it may be worthwhile to use exact extraction, but we are unable to show significant improvements with this setup -- only 2/11 benchmarks show any improvement over the greedy extractor.
+We also observe that egg's CBC solver outperforms our good\_lp-based solver in terms of time to solution. We believe this to be due to differences in how the two implementations handle cycles. As specified in the constraints in [Design Extraction](#design-extraction), a subgraph extracted from an e-graph should not contain cycles. To address this, Egg's cbc solver filters cycles before formulating a linear programming problem and solving it with COIN-Or Branch-and-Cut's solver. Our good\_lp solver handles cycles with an acyclicity constraint which must be respected by solver. [Prior work](https://arxiv.org/pdf/2101.01332) has shown that the acyclity constraint is the main bottleneck for linear-programming-based e-graph extraction.
+
+### ASIC Synthesis
+
+We also compare the area (µm²) of synthesized ASIC designs extracted using greedy and exact extraction. We use another e-graph-based logic synthesis tool, called msynth, which operates similarly to lvv, but can synthesize ASIC designs using a standard cell library. Synthesizing an ASIC design using exact extraction becomes prohibitive faster than synthesis targetting an FPGA due to the larger design search space. The transformation from digital logic to standard cells is encoded in the rewrite rules, so both transformation from logic gates to standard cells and optimization take place simultaneously. We also compare against the Synopsys commercial design compiler to show the design quality a tuned EDA tool can achieve.
+
+<!--./scripts/msynth-iscas85.sh (with -n 1, then -n 4 until c17-highs and c17-egg_cbc improve improves and ) ;./scripts/parse_msynth.sh   -->
+| Benchmark | Greedy Area | HiGHS Area | egg CBC Area | CBC Area   | Synopsys |
+|-----------|-------------|------------|--------------|------------|----------|
+| c1355     | 296.86      | 434.11     | Infeasible   | 439.17     | 254.56   |
+| c17       | 7.18        | 6.92       | Infeasible   | 7.18       | 6.92     |
+| c1908     | 305.10      | 401.93     | 423.47       | Infeasible | 229.29   |
+| c2670     | 592.12      | 762.89     | 781.51       | Infeasible | 424.00   |
+| c3540     | 895.36      | 979.95     | Infeasible   | Error      | 537.59   |
+| c432      | 185.93      | 176.36     | 187.53       | 187.53     | 107.46   |
+| c499      | 259.08      | 272.38     | 272.38       | 272.38     | 255.63   |
+| c5315     | 1327.07     | Error      | Infeasible   | Error      | 813.43   |
+| c6288     | 3264.89     | Error      | Infeasible   | Error      | 1239.83  |
+| c7552     | 1617.00     | Error      | Infeasible   | Error      | 913.18   |
+| c880      | 257.22      | 265.73     | Infeasible   | Error      | 224.24   |
+
+| Benchmark | Greedy Time | HiGHS Time | egg CBC Time | egg CBC Time |
+|-----------|-------------|------------|--------------|------------|
+| c1355     | 0.020       | 0.484      | Infeasible   | 0.209      |
+| c17       | 0.009       | 0.039      | Infeasible   | 143.69     |
+| c1908     | 0.035       | 193.03     | 603.74       | Infeasible |
+| c2670     | 0.025       | 277.81     | 611.29       | Infeasible |
+| c3540     | 0.037       | 100.99     | Infeasible   | Error      |
+| c432      | 0.028       | 127.04     | 604.09       | 178.49     |
+| c499      | 0.024       | 39.59      | 19.22        | 0.197      |
+| c5315     | 0.136       | Error      | Infeasible   | Infeasible |
+| c6288     | 0.627       | Error      | Infeasible   | Error      |
+| c7552     | 0.108       | Error      | Infeasible   | Error      |
+| c880      | 0.032       | 8.49       | Infeasible   | Error      |
+
+As shown in the tables, many designs generate problems the cbc solver cannot handle. The entries labelled infeasible indicate the solver (mistakenly) identified the problem to be infeasible. When running with an alternative solver (e.g., HiGHs) a correct design is generated, which we verify with Yosys [equivalence checking](https://yosyshq.readthedocs.io/projects/yosys/en/latest/cmd/equiv_simple.html). Not all solvers implement support for [descriptive error messages](https://stackoverflow.com/questions/37593986/cbc-know-why-a-program-is-infeasible), making it is difficult to determine the source of the error, and how we might modify the problem formulation to work with the solver. The issues are not only found in egg's exact extractor implementation using cbc -- we find similar issues when using cbc through good\_lp.
+Some errors (e.g., errors when using HiGHS) occur due to time limitations. Since we are unable to perform exact extraction over large e-graphs, we must restrict the size of the e-graph by limiting the number of rewrites. By doing so, it is possible for some logic not to be mapped to standard cells. In this scenario, the tool emits an error instead of an incorrect design.
+Through this evaluation, we observe that greedy extraction cannot achieve the design quality of optimized EDA tools, but it is impractical to achieve high quality designs using exact extraction, due to its poor scalability. This motivates novel extraction approaches that find a better trade between solution quality and scalability.
+
+## Conclusion
+
+The end goal of the project changed after the proposal. Initially, we aimed to integrate an efficient extraction algorithm, called [SmoothE](https://www.csl.cornell.edu/~zhiruz/pdfs/smoothe-asplos2025.pdf), into the EDA tool used throughout this project. As a stepping stone towards an implementation, we decided to first implement a linear programming-based extraction algorithm.
+Getting our LP solver implementation to emit correct results took more effort than expected. At the same time, the EDA tool had only recently added support for ASIC logic synthesis using a standard cell library, so exact extraction had not yet been fully implemented and tested. For this reason we decided to focus on developing a correct implementation of LP extraction. Despite the less ambitious end goal, there were numerous challenges.
+
+Long synthesis times for exact extraction made debugging challenging. Working with simple, fast-to-synthesize test cases is not enough. Simple test cases' e-graphs are not representative of complex designs with thousands of e-nodes, hundreds of thousands of constraints, and many cycles.
+The size and complexity of logic synthesis for ASICs revealed the limitations of solver libraries, which we sought to address by making the the EDA tool's exact extraction implementation agnostic to the solver.
\ No newline at end of file
diff --git a/content/blog/2025-5-13-superopt/simple_2_output_before.svg b/content/blog/2025-5-13-superopt/simple_2_output_before.svg
new file mode 100644
index 000000000..ca4188d3e
--- /dev/null
+++ b/content/blog/2025-5-13-superopt/simple_2_output_before.svg
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 12.2.1 (0)
+ -->
+<!-- Pages: 1 -->
+<svg width="158pt" height="230pt"
+ viewBox="0.00 0.00 158.00 230.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 226)">
+<polygon fill="white" stroke="none" points="-4,4 -4,-226 154,-226 154,4 -4,4"/>
+<g id="clust1" class="cluster">
+<title>outer_cluster_2</title>
+</g>
+<g id="clust2" class="cluster">
+<title>cluster_2</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M25,-90C25,-90 61,-90 61,-90 67,-90 73,-96 73,-102 73,-102 73,-120 73,-120 73,-126 67,-132 61,-132 61,-132 25,-132 25,-132 19,-132 13,-126 13,-120 13,-120 13,-102 13,-102 13,-96 19,-90 25,-90"/>
+</g>
+<g id="clust4" class="cluster">
+<title>outer_cluster_3</title>
+</g>
+<g id="clust5" class="cluster">
+<title>cluster_3</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M91,-90C91,-90 127,-90 127,-90 133,-90 139,-96 139,-102 139,-102 139,-120 139,-120 139,-126 133,-132 127,-132 127,-132 91,-132 91,-132 85,-132 79,-126 79,-120 79,-120 79,-102 79,-102 79,-96 85,-90 91,-90"/>
+</g>
+<g id="clust7" class="cluster">
+<title>outer_cluster_4</title>
+</g>
+<g id="clust8" class="cluster">
+<title>cluster_4</title>
+<path fill="#ffffb3" stroke="black" stroke-width="2" stroke-dasharray="5,2" d="M58,-169C58,-169 94,-169 94,-169 100,-169 106,-175 106,-181 106,-181 106,-199 106,-199 106,-205 100,-211 94,-211 94,-211 58,-211 58,-211 52,-211 46,-205 46,-199 46,-199 46,-181 46,-181 46,-175 52,-169 58,-169"/>
+</g>
+<g id="clust10" class="cluster">
+<title>outer_cluster_0</title>
+</g>
+<g id="clust11" class="cluster">
+<title>cluster_0</title>
+<path fill="#ffffb3" stroke="black" stroke-width="2" stroke-dasharray="5,2" d="M23,-11C23,-11 59,-11 59,-11 65,-11 71,-17 71,-23 71,-23 71,-41 71,-41 71,-47 65,-53 59,-53 59,-53 23,-53 23,-53 17,-53 11,-47 11,-41 11,-41 11,-23 11,-23 11,-17 17,-11 23,-11"/>
+</g>
+<g id="clust13" class="cluster">
+<title>outer_cluster_1</title>
+</g>
+<g id="clust14" class="cluster">
+<title>cluster_1</title>
+<path fill="#ffffb3" stroke="black" stroke-width="2" stroke-dasharray="5,2" d="M90,-11C90,-11 126,-11 126,-11 132,-11 138,-17 138,-23 138,-23 138,-41 138,-41 138,-47 132,-53 126,-53 126,-53 90,-53 90,-53 84,-53 78,-47 78,-41 78,-41 78,-23 78,-23 78,-17 84,-11 90,-11"/>
+</g>
+<!-- 2.0&#45;&gt;0.0 -->
+<g id="edge1" class="edge">
+<title>2.0:s&#45;&gt;0.0</title>
+<path fill="none" stroke="black" d="M33.88,-95C33.88,-82.02 35.44,-67.61 37.1,-55.95"/>
+<polygon fill="black" stroke="black" points="37.74,-59.74 37.57,-54.44 34.4,-58.69 37.74,-59.74"/>
+</g>
+<!-- 2.0&#45;&gt;1.0 -->
+<g id="edge2" class="edge">
+<title>2.0:s&#45;&gt;1.0</title>
+<path fill="none" stroke="black" d="M52.12,-95C52.12,-78.24 63.53,-63.97 76.03,-53.36"/>
+<polygon fill="black" stroke="black" points="74.72,-57.23 76.95,-52.42 72.21,-54.79 74.72,-57.23"/>
+</g>
+<!-- 3.0&#45;&gt;0.0 -->
+<g id="edge3" class="edge">
+<title>3.0:s&#45;&gt;0.0</title>
+<path fill="none" stroke="black" d="M99.5,-95C99.5,-84.81 82.56,-67.63 66.91,-53.94"/>
+<polygon fill="black" stroke="black" points="71.7,-54.47 66.46,-53.7 70.08,-57.57 71.7,-54.47"/>
+</g>
+<!-- 3.0&#45;&gt;1.0 -->
+<g id="edge4" class="edge">
+<title>3.0:s&#45;&gt;1.0</title>
+<path fill="none" stroke="black" d="M118.5,-95C118.5,-82.01 116.23,-67.71 113.8,-56.11"/>
+<polygon fill="black" stroke="black" points="116.65,-58.28 113.06,-54.39 113.44,-59.67 116.65,-58.28"/>
+</g>
+<!-- 4.0&#45;&gt;2.0 -->
+<g id="edge5" class="edge">
+<title>4.0:s&#45;&gt;2.0</title>
+<path fill="none" stroke="black" d="M67.06,-174C67.06,-160.33 61.92,-146.05 56.39,-134.64"/>
+<polygon fill="black" stroke="black" points="59.71,-136.26 55.37,-133.23 56.87,-138.31 59.71,-136.26"/>
+</g>
+<!-- 4.0&#45;&gt;3.0 -->
+<g id="edge6" class="edge">
+<title>4.0:s&#45;&gt;3.0</title>
+<path fill="none" stroke="black" d="M84.94,-174C84.94,-160.33 90.08,-146.05 95.61,-134.64"/>
+<polygon fill="black" stroke="black" points="95.13,-138.31 96.63,-133.23 92.29,-136.26 95.13,-138.31"/>
+</g>
+<!-- 2.0 -->
+<g id="node1" class="node">
+<title>2.0</title>
+<g id="a_node1"><a xlink:title="2: 2.0">
+<path fill="white" stroke="none" d="M34.42,-95C34.42,-95 51.58,-95 51.58,-95 56.92,-95 62.25,-100.33 62.25,-105.67 62.25,-105.67 62.25,-116.33 62.25,-116.33 62.25,-121.67 56.92,-127 51.58,-127 51.58,-127 34.42,-127 34.42,-127 29.08,-127 23.75,-121.67 23.75,-116.33 23.75,-116.33 23.75,-105.67 23.75,-105.67 23.75,-100.33 29.08,-95 34.42,-95"/>
+<text text-anchor="start" x="28.75" y="-105.2" font-family="Helvetica,sans-Serif" font-size="14.00">AND</text>
+<path fill="none" stroke="black" d="M34.42,-95C34.42,-95 51.58,-95 51.58,-95 56.92,-95 62.25,-100.33 62.25,-105.67 62.25,-105.67 62.25,-116.33 62.25,-116.33 62.25,-121.67 56.92,-127 51.58,-127 51.58,-127 34.42,-127 34.42,-127 29.08,-127 23.75,-121.67 23.75,-116.33 23.75,-116.33 23.75,-105.67 23.75,-105.67 23.75,-100.33 29.08,-95 34.42,-95"/>
+</a>
+</g>
+</g>
+<!-- 0.0 -->
+<g id="node2" class="node">
+<title>0.0</title>
+<g id="a_node2"><a xlink:title="0: 0.0">
+<path fill="white" stroke="none" d="M35.67,-16C35.67,-16 46.33,-16 46.33,-16 51.67,-16 57,-21.33 57,-26.67 57,-26.67 57,-37.33 57,-37.33 57,-42.67 51.67,-48 46.33,-48 46.33,-48 35.67,-48 35.67,-48 30.33,-48 25,-42.67 25,-37.33 25,-37.33 25,-26.67 25,-26.67 25,-21.33 30.33,-16 35.67,-16"/>
+<text text-anchor="start" x="37.25" y="-26.2" font-family="Helvetica,sans-Serif" font-size="14.00">a</text>
+<path fill="none" stroke="black" d="M35.67,-16C35.67,-16 46.33,-16 46.33,-16 51.67,-16 57,-21.33 57,-26.67 57,-26.67 57,-37.33 57,-37.33 57,-42.67 51.67,-48 46.33,-48 46.33,-48 35.67,-48 35.67,-48 30.33,-48 25,-42.67 25,-37.33 25,-37.33 25,-26.67 25,-26.67 25,-21.33 30.33,-16 35.67,-16"/>
+</a>
+</g>
+</g>
+<!-- 1.0 -->
+<g id="node3" class="node">
+<title>1.0</title>
+<g id="a_node3"><a xlink:title="1: 1.0">
+<path fill="white" stroke="none" d="M102.67,-16C102.67,-16 113.33,-16 113.33,-16 118.67,-16 124,-21.33 124,-26.67 124,-26.67 124,-37.33 124,-37.33 124,-42.67 118.67,-48 113.33,-48 113.33,-48 102.67,-48 102.67,-48 97.33,-48 92,-42.67 92,-37.33 92,-37.33 92,-26.67 92,-26.67 92,-21.33 97.33,-16 102.67,-16"/>
+<text text-anchor="start" x="104.25" y="-26.2" font-family="Helvetica,sans-Serif" font-size="14.00">b</text>
+<path fill="none" stroke="black" d="M102.67,-16C102.67,-16 113.33,-16 113.33,-16 118.67,-16 124,-21.33 124,-26.67 124,-26.67 124,-37.33 124,-37.33 124,-42.67 118.67,-48 113.33,-48 113.33,-48 102.67,-48 102.67,-48 97.33,-48 92,-42.67 92,-37.33 92,-37.33 92,-26.67 92,-26.67 92,-21.33 97.33,-16 102.67,-16"/>
+</a>
+</g>
+</g>
+<!-- 3.0 -->
+<g id="node4" class="node">
+<title>3.0</title>
+<g id="a_node4"><a xlink:title="3: 3.0">
+<path fill="white" stroke="none" d="M99.67,-95C99.67,-95 118.33,-95 118.33,-95 123.67,-95 129,-100.33 129,-105.67 129,-105.67 129,-116.33 129,-116.33 129,-121.67 123.67,-127 118.33,-127 118.33,-127 99.67,-127 99.67,-127 94.33,-127 89,-121.67 89,-116.33 89,-116.33 89,-105.67 89,-105.67 89,-100.33 94.33,-95 99.67,-95"/>
+<text text-anchor="start" x="94" y="-105.2" font-family="Helvetica,sans-Serif" font-size="14.00">XOR</text>
+<path fill="none" stroke="black" d="M99.67,-95C99.67,-95 118.33,-95 118.33,-95 123.67,-95 129,-100.33 129,-105.67 129,-105.67 129,-116.33 129,-116.33 129,-121.67 123.67,-127 118.33,-127 118.33,-127 99.67,-127 99.67,-127 94.33,-127 89,-121.67 89,-116.33 89,-116.33 89,-105.67 89,-105.67 89,-100.33 94.33,-95 99.67,-95"/>
+</a>
+</g>
+</g>
+<!-- 4.0 -->
+<g id="node5" class="node">
+<title>4.0</title>
+<g id="a_node5"><a xlink:title="4: 4.0">
+<path fill="white" stroke="none" d="M67.79,-174C67.79,-174 84.21,-174 84.21,-174 89.54,-174 94.88,-179.33 94.88,-184.67 94.88,-184.67 94.88,-195.33 94.88,-195.33 94.88,-200.67 89.54,-206 84.21,-206 84.21,-206 67.79,-206 67.79,-206 62.46,-206 57.12,-200.67 57.12,-195.33 57.12,-195.33 57.12,-184.67 57.12,-184.67 57.12,-179.33 62.46,-174 67.79,-174"/>
+<text text-anchor="start" x="62.12" y="-184.2" font-family="Helvetica,sans-Serif" font-size="14.00">BUS</text>
+<path fill="none" stroke="black" d="M67.79,-174C67.79,-174 84.21,-174 84.21,-174 89.54,-174 94.88,-179.33 94.88,-184.67 94.88,-184.67 94.88,-195.33 94.88,-195.33 94.88,-200.67 89.54,-206 84.21,-206 84.21,-206 67.79,-206 67.79,-206 62.46,-206 57.12,-200.67 57.12,-195.33 57.12,-195.33 57.12,-184.67 57.12,-184.67 57.12,-179.33 62.46,-174 67.79,-174"/>
+</a>
+</g>
+</g>
+</g>
+</svg>
diff --git a/content/blog/2025-5-13-superopt/simple_2_output_lvv_after.svg b/content/blog/2025-5-13-superopt/simple_2_output_lvv_after.svg
new file mode 100644
index 000000000..9783ba4bc
--- /dev/null
+++ b/content/blog/2025-5-13-superopt/simple_2_output_lvv_after.svg
@@ -0,0 +1,235 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 12.2.1 (0)
+ -->
+<!-- Pages: 1 -->
+<svg width="289pt" height="230pt"
+ viewBox="0.00 0.00 289.00 230.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 226)">
+<polygon fill="white" stroke="none" points="-4,4 -4,-226 285,-226 285,4 -4,4"/>
+<g id="clust1" class="cluster">
+<title>outer_cluster_2</title>
+</g>
+<g id="clust2" class="cluster">
+<title>cluster_2</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M90,-11C90,-11 126,-11 126,-11 132,-11 138,-17 138,-23 138,-23 138,-41 138,-41 138,-47 132,-53 126,-53 126,-53 90,-53 90,-53 84,-53 78,-47 78,-41 78,-41 78,-23 78,-23 78,-17 84,-11 90,-11"/>
+</g>
+<g id="clust4" class="cluster">
+<title>outer_cluster_5</title>
+</g>
+<g id="clust5" class="cluster">
+<title>cluster_5</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M33,-90C33,-90 127,-90 127,-90 133,-90 139,-96 139,-102 139,-102 139,-120 139,-120 139,-126 133,-132 127,-132 127,-132 33,-132 33,-132 27,-132 21,-126 21,-120 21,-120 21,-102 21,-102 21,-96 27,-90 33,-90"/>
+</g>
+<g id="clust7" class="cluster">
+<title>outer_cluster_3</title>
+</g>
+<g id="clust8" class="cluster">
+<title>cluster_3</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M157,-90C157,-90 251,-90 251,-90 257,-90 263,-96 263,-102 263,-102 263,-120 263,-120 263,-126 257,-132 251,-132 251,-132 157,-132 157,-132 151,-132 145,-126 145,-120 145,-120 145,-102 145,-102 145,-96 151,-90 157,-90"/>
+</g>
+<g id="clust10" class="cluster">
+<title>outer_cluster_4</title>
+</g>
+<g id="clust11" class="cluster">
+<title>cluster_4</title>
+<path fill="#ffffb3" stroke="black" stroke-dasharray="5,2" d="M23,-11C23,-11 59,-11 59,-11 65,-11 71,-17 71,-23 71,-23 71,-41 71,-41 71,-47 65,-53 59,-53 59,-53 23,-53 23,-53 17,-53 11,-47 11,-41 11,-41 11,-23 11,-23 11,-17 17,-11 23,-11"/>
+</g>
+<g id="clust13" class="cluster">
+<title>outer_cluster_6</title>
+</g>
+<g id="clust14" class="cluster">
+<title>cluster_6</title>
+<path fill="#ffffb3" stroke="black" stroke-width="2" stroke-dasharray="5,2" d="M124,-169C124,-169 160,-169 160,-169 166,-169 172,-175 172,-181 172,-181 172,-199 172,-199 172,-205 166,-211 160,-211 160,-211 124,-211 124,-211 118,-211 112,-205 112,-199 112,-199 112,-181 112,-181 112,-175 118,-169 124,-169"/>
+</g>
+<g id="clust16" class="cluster">
+<title>outer_cluster_0</title>
+</g>
+<g id="clust17" class="cluster">
+<title>cluster_0</title>
+<path fill="#ffffb3" stroke="black" stroke-width="2" stroke-dasharray="5,2" d="M222,-11C222,-11 258,-11 258,-11 264,-11 270,-17 270,-23 270,-23 270,-41 270,-41 270,-47 264,-53 258,-53 258,-53 222,-53 222,-53 216,-53 210,-47 210,-41 210,-41 210,-23 210,-23 210,-17 216,-11 222,-11"/>
+</g>
+<g id="clust19" class="cluster">
+<title>outer_cluster_1</title>
+</g>
+<g id="clust20" class="cluster">
+<title>cluster_1</title>
+<path fill="#ffffb3" stroke="black" stroke-width="2" stroke-dasharray="5,2" d="M156,-11C156,-11 192,-11 192,-11 198,-11 204,-17 204,-23 204,-23 204,-41 204,-41 204,-47 198,-53 192,-53 192,-53 156,-53 156,-53 150,-53 144,-47 144,-41 144,-41 144,-23 144,-23 144,-17 150,-11 156,-11"/>
+</g>
+<!-- 5.1&#45;&gt;2.0 -->
+<g id="edge2" class="edge">
+<title>5.1:s&#45;&gt;2.0</title>
+<path fill="none" stroke="black" d="M51,-95C51,-77.68 63.2,-63.11 76.32,-52.46"/>
+<polygon fill="black" stroke="black" points="74.74,-56.62 76.95,-51.81 72.22,-54.19 74.74,-56.62"/>
+</g>
+<!-- 5.1&#45;&gt;4.0 -->
+<g id="edge1" class="edge">
+<title>5.1:s&#45;&gt;4.0</title>
+<path fill="none" stroke="black" d="M39.83,-95C39.83,-82.22 40.08,-67.96 40.35,-56.34"/>
+<polygon fill="black" stroke="black" points="41.95,-59.59 40.44,-54.51 38.45,-59.42 41.95,-59.59"/>
+</g>
+<!-- 5.1&#45;&gt;1.0 -->
+<g id="edge3" class="edge">
+<title>5.1:s&#45;&gt;1.0</title>
+<path fill="none" stroke="black" d="M62.17,-95C62.17,-56.7 105.87,-75.21 139,-56 140.53,-55.11 142.09,-54.18 143.66,-53.23"/>
+<polygon fill="black" stroke="black" points="140.3,-58.56 142.87,-53.93 137.97,-55.95 140.3,-58.56"/>
+</g>
+<!-- 5.0&#45;&gt;2.0 -->
+<g id="edge6" class="edge">
+<title>5.0:s&#45;&gt;2.0</title>
+<path fill="none" stroke="black" d="M120.17,-95C120.17,-81.95 117.54,-67.64 114.73,-56.06"/>
+<polygon fill="black" stroke="black" points="117.69,-58 113.85,-54.35 114.57,-59.6 117.69,-58"/>
+</g>
+<!-- 5.0&#45;&gt;4.0 -->
+<g id="edge4" class="edge">
+<title>5.0:s&#45;&gt;4.0</title>
+<path fill="none" stroke="black" d="M97.83,-95C97.83,-77.7 85.67,-63.14 72.59,-52.48"/>
+<polygon fill="black" stroke="black" points="76.68,-54.37 72.02,-51.85 74.09,-56.73 76.68,-54.37"/>
+</g>
+<!-- 5.0&#45;&gt;1.0 -->
+<g id="edge5" class="edge">
+<title>5.0:s&#45;&gt;1.0</title>
+<path fill="none" stroke="black" d="M109,-95C109,-84.24 127.89,-67.06 145.31,-53.51"/>
+<polygon fill="black" stroke="black" points="141.46,-57.83 144.86,-53.77 139.67,-54.83 141.46,-57.83"/>
+</g>
+<!-- 3.0&#45;&gt;2.0 -->
+<g id="edge9" class="edge">
+<title>3.0:s&#45;&gt;2.0</title>
+<path fill="none" stroke="black" d="M186.17,-95C186.17,-88.63 160.32,-69.08 138.36,-53.62"/>
+<polygon fill="black" stroke="black" points="142.73,-57.81 138.74,-54.31 139.68,-59.53 142.73,-57.81"/>
+</g>
+<!-- 3.0&#45;&gt;1.0 -->
+<g id="edge8" class="edge">
+<title>3.0:s&#45;&gt;1.0</title>
+<path fill="none" stroke="black" d="M175,-95C175,-82.22 174.78,-67.96 174.55,-56.34"/>
+<polygon fill="black" stroke="black" points="176.43,-59.44 174.48,-54.51 172.93,-59.58 176.43,-59.44"/>
+</g>
+<!-- 3.0&#45;&gt;0.0 -->
+<g id="edge7" class="edge">
+<title>3.0:s&#45;&gt;0.0</title>
+<path fill="none" stroke="black" d="M163.83,-95C163.83,-88.69 189.33,-68.92 210.82,-53.39"/>
+<polygon fill="black" stroke="black" points="206.36,-56.85 210.48,-53.51 205.18,-53.55 206.36,-56.85"/>
+</g>
+<!-- 3.1&#45;&gt;2.0 -->
+<g id="edge11" class="edge">
+<title>3.1:s&#45;&gt;2.0</title>
+<path fill="none" stroke="black" d="M233,-95C233,-51.41 181.36,-76.71 143,-56 141.38,-55.13 139.74,-54.2 138.1,-53.24"/>
+<polygon fill="black" stroke="black" points="141.36,-58.72 138.39,-54.34 137.98,-59.62 141.36,-58.72"/>
+</g>
+<!-- 3.1&#45;&gt;1.0 -->
+<g id="edge12" class="edge">
+<title>3.1:s&#45;&gt;1.0</title>
+<path fill="none" stroke="black" d="M244.17,-95C244.17,-83.86 224.04,-66.86 205.34,-53.49"/>
+<polygon fill="black" stroke="black" points="209.45,-55.79 204.95,-52.99 206.72,-57.99 209.45,-55.79"/>
+</g>
+<!-- 3.1&#45;&gt;0.0 -->
+<g id="edge10" class="edge">
+<title>3.1:s&#45;&gt;0.0</title>
+<path fill="none" stroke="black" d="M221.83,-95C221.83,-81.75 225.7,-67.53 229.87,-56.05"/>
+<polygon fill="black" stroke="black" points="230.2,-59.67 230.59,-54.39 226.99,-58.28 230.2,-59.67"/>
+</g>
+<!-- 6.0&#45;&gt;5.0 -->
+<g id="edge14" class="edge">
+<title>6.0:s&#45;&gt;5.0</title>
+<path fill="none" stroke="black" d="M150.94,-174C150.94,-158.9 142.3,-144.73 132.86,-133.76"/>
+<polygon fill="black" stroke="black" points="136.76,-134.49 131.71,-132.91 134.67,-137.3 136.76,-134.49"/>
+</g>
+<!-- 6.0&#45;&gt;3.0 -->
+<g id="edge13" class="edge">
+<title>6.0:s&#45;&gt;3.0</title>
+<path fill="none" stroke="black" d="M133.06,-174C133.06,-158.9 141.7,-144.73 151.14,-133.76"/>
+<polygon fill="black" stroke="black" points="149.33,-137.3 152.29,-132.91 147.24,-134.49 149.33,-137.3"/>
+</g>
+<!-- 2.0 -->
+<g id="node1" class="node">
+<title>2.0</title>
+<g id="a_node1"><a xlink:title="2: 2.0">
+<path fill="white" stroke="none" d="M102.67,-16C102.67,-16 113.33,-16 113.33,-16 118.67,-16 124,-21.33 124,-26.67 124,-26.67 124,-37.33 124,-37.33 124,-42.67 118.67,-48 113.33,-48 113.33,-48 102.67,-48 102.67,-48 97.33,-48 92,-42.67 92,-37.33 92,-37.33 92,-26.67 92,-26.67 92,-21.33 97.33,-16 102.67,-16"/>
+<text text-anchor="start" x="104.25" y="-26.2" font-family="Helvetica,sans-Serif" font-size="14.00">a</text>
+<path fill="none" stroke="black" d="M102.67,-16C102.67,-16 113.33,-16 113.33,-16 118.67,-16 124,-21.33 124,-26.67 124,-26.67 124,-37.33 124,-37.33 124,-42.67 118.67,-48 113.33,-48 113.33,-48 102.67,-48 102.67,-48 97.33,-48 92,-42.67 92,-37.33 92,-37.33 92,-26.67 92,-26.67 92,-21.33 97.33,-16 102.67,-16"/>
+</a>
+</g>
+</g>
+<!-- 5.1 -->
+<g id="node2" class="node">
+<title>5.1</title>
+<g id="a_node2"><a xlink:title="5: 5.1">
+<path fill="white" stroke="none" d="M43.92,-95C43.92,-95 58.08,-95 58.08,-95 63.42,-95 68.75,-100.33 68.75,-105.67 68.75,-105.67 68.75,-116.33 68.75,-116.33 68.75,-121.67 63.42,-127 58.08,-127 58.08,-127 43.92,-127 43.92,-127 38.58,-127 33.25,-121.67 33.25,-116.33 33.25,-116.33 33.25,-105.67 33.25,-105.67 33.25,-100.33 38.58,-95 43.92,-95"/>
+<text text-anchor="start" x="38.25" y="-105.2" font-family="Helvetica,sans-Serif" font-size="14.00">LUT</text>
+<path fill="none" stroke="black" d="M43.92,-95C43.92,-95 58.08,-95 58.08,-95 63.42,-95 68.75,-100.33 68.75,-105.67 68.75,-105.67 68.75,-116.33 68.75,-116.33 68.75,-121.67 63.42,-127 58.08,-127 58.08,-127 43.92,-127 43.92,-127 38.58,-127 33.25,-121.67 33.25,-116.33 33.25,-116.33 33.25,-105.67 33.25,-105.67 33.25,-100.33 38.58,-95 43.92,-95"/>
+</a>
+</g>
+</g>
+<!-- 4.0 -->
+<g id="node3" class="node">
+<title>4.0</title>
+<g id="a_node3"><a xlink:title="4: 4.0">
+<path fill="white" stroke="none" d="M35.67,-16C35.67,-16 46.33,-16 46.33,-16 51.67,-16 57,-21.33 57,-26.67 57,-26.67 57,-37.33 57,-37.33 57,-42.67 51.67,-48 46.33,-48 46.33,-48 35.67,-48 35.67,-48 30.33,-48 25,-42.67 25,-37.33 25,-37.33 25,-26.67 25,-26.67 25,-21.33 30.33,-16 35.67,-16"/>
+<text text-anchor="start" x="37.25" y="-26.2" font-family="Helvetica,sans-Serif" font-size="14.00">6</text>
+<path fill="none" stroke="black" d="M35.67,-16C35.67,-16 46.33,-16 46.33,-16 51.67,-16 57,-21.33 57,-26.67 57,-26.67 57,-37.33 57,-37.33 57,-42.67 51.67,-48 46.33,-48 46.33,-48 35.67,-48 35.67,-48 30.33,-48 25,-42.67 25,-37.33 25,-37.33 25,-26.67 25,-26.67 25,-21.33 30.33,-16 35.67,-16"/>
+</a>
+</g>
+</g>
+<!-- 1.0 -->
+<g id="node4" class="node">
+<title>1.0</title>
+<g id="a_node4"><a xlink:title="1: 1.0">
+<path fill="white" stroke="none" d="M168.67,-16C168.67,-16 179.33,-16 179.33,-16 184.67,-16 190,-21.33 190,-26.67 190,-26.67 190,-37.33 190,-37.33 190,-42.67 184.67,-48 179.33,-48 179.33,-48 168.67,-48 168.67,-48 163.33,-48 158,-42.67 158,-37.33 158,-37.33 158,-26.67 158,-26.67 158,-21.33 163.33,-16 168.67,-16"/>
+<text text-anchor="start" x="170.25" y="-26.2" font-family="Helvetica,sans-Serif" font-size="14.00">b</text>
+<path fill="none" stroke="black" d="M168.67,-16C168.67,-16 179.33,-16 179.33,-16 184.67,-16 190,-21.33 190,-26.67 190,-26.67 190,-37.33 190,-37.33 190,-42.67 184.67,-48 179.33,-48 179.33,-48 168.67,-48 168.67,-48 163.33,-48 158,-42.67 158,-37.33 158,-37.33 158,-26.67 158,-26.67 158,-21.33 163.33,-16 168.67,-16"/>
+</a>
+</g>
+</g>
+<!-- 5.0 -->
+<g id="node5" class="node">
+<title>5.0</title>
+<g id="a_node5"><a xlink:title="5: 5.0">
+<path fill="white" stroke="none" d="M101.92,-95C101.92,-95 116.08,-95 116.08,-95 121.42,-95 126.75,-100.33 126.75,-105.67 126.75,-105.67 126.75,-116.33 126.75,-116.33 126.75,-121.67 121.42,-127 116.08,-127 116.08,-127 101.92,-127 101.92,-127 96.58,-127 91.25,-121.67 91.25,-116.33 91.25,-116.33 91.25,-105.67 91.25,-105.67 91.25,-100.33 96.58,-95 101.92,-95"/>
+<text text-anchor="start" x="96.25" y="-105.2" font-family="Helvetica,sans-Serif" font-size="14.00">LUT</text>
+<path fill="none" stroke="black" d="M101.92,-95C101.92,-95 116.08,-95 116.08,-95 121.42,-95 126.75,-100.33 126.75,-105.67 126.75,-105.67 126.75,-116.33 126.75,-116.33 126.75,-121.67 121.42,-127 116.08,-127 116.08,-127 101.92,-127 101.92,-127 96.58,-127 91.25,-121.67 91.25,-116.33 91.25,-116.33 91.25,-105.67 91.25,-105.67 91.25,-100.33 96.58,-95 101.92,-95"/>
+</a>
+</g>
+</g>
+<!-- 3.0 -->
+<g id="node6" class="node">
+<title>3.0</title>
+<g id="a_node6"><a xlink:title="3: 3.0">
+<path fill="white" stroke="none" d="M167.92,-95C167.92,-95 182.08,-95 182.08,-95 187.42,-95 192.75,-100.33 192.75,-105.67 192.75,-105.67 192.75,-116.33 192.75,-116.33 192.75,-121.67 187.42,-127 182.08,-127 182.08,-127 167.92,-127 167.92,-127 162.58,-127 157.25,-121.67 157.25,-116.33 157.25,-116.33 157.25,-105.67 157.25,-105.67 157.25,-100.33 162.58,-95 167.92,-95"/>
+<text text-anchor="start" x="162.25" y="-105.2" font-family="Helvetica,sans-Serif" font-size="14.00">LUT</text>
+<path fill="none" stroke="black" d="M167.92,-95C167.92,-95 182.08,-95 182.08,-95 187.42,-95 192.75,-100.33 192.75,-105.67 192.75,-105.67 192.75,-116.33 192.75,-116.33 192.75,-121.67 187.42,-127 182.08,-127 182.08,-127 167.92,-127 167.92,-127 162.58,-127 157.25,-121.67 157.25,-116.33 157.25,-116.33 157.25,-105.67 157.25,-105.67 157.25,-100.33 162.58,-95 167.92,-95"/>
+</a>
+</g>
+</g>
+<!-- 0.0 -->
+<g id="node7" class="node">
+<title>0.0</title>
+<g id="a_node7"><a xlink:title="0: 0.0">
+<path fill="white" stroke="none" d="M234.67,-16C234.67,-16 245.33,-16 245.33,-16 250.67,-16 256,-21.33 256,-26.67 256,-26.67 256,-37.33 256,-37.33 256,-42.67 250.67,-48 245.33,-48 245.33,-48 234.67,-48 234.67,-48 229.33,-48 224,-42.67 224,-37.33 224,-37.33 224,-26.67 224,-26.67 224,-21.33 229.33,-16 234.67,-16"/>
+<text text-anchor="start" x="236.25" y="-26.2" font-family="Helvetica,sans-Serif" font-size="14.00">8</text>
+<path fill="none" stroke="black" d="M234.67,-16C234.67,-16 245.33,-16 245.33,-16 250.67,-16 256,-21.33 256,-26.67 256,-26.67 256,-37.33 256,-37.33 256,-42.67 250.67,-48 245.33,-48 245.33,-48 234.67,-48 234.67,-48 229.33,-48 224,-42.67 224,-37.33 224,-37.33 224,-26.67 224,-26.67 224,-21.33 229.33,-16 234.67,-16"/>
+</a>
+</g>
+</g>
+<!-- 3.1 -->
+<g id="node8" class="node">
+<title>3.1</title>
+<g id="a_node8"><a xlink:title="3: 3.1">
+<path fill="white" stroke="none" d="M225.92,-95C225.92,-95 240.08,-95 240.08,-95 245.42,-95 250.75,-100.33 250.75,-105.67 250.75,-105.67 250.75,-116.33 250.75,-116.33 250.75,-121.67 245.42,-127 240.08,-127 240.08,-127 225.92,-127 225.92,-127 220.58,-127 215.25,-121.67 215.25,-116.33 215.25,-116.33 215.25,-105.67 215.25,-105.67 215.25,-100.33 220.58,-95 225.92,-95"/>
+<text text-anchor="start" x="220.25" y="-105.2" font-family="Helvetica,sans-Serif" font-size="14.00">LUT</text>
+<path fill="none" stroke="black" d="M225.92,-95C225.92,-95 240.08,-95 240.08,-95 245.42,-95 250.75,-100.33 250.75,-105.67 250.75,-105.67 250.75,-116.33 250.75,-116.33 250.75,-121.67 245.42,-127 240.08,-127 240.08,-127 225.92,-127 225.92,-127 220.58,-127 215.25,-121.67 215.25,-116.33 215.25,-116.33 215.25,-105.67 215.25,-105.67 215.25,-100.33 220.58,-95 225.92,-95"/>
+</a>
+</g>
+</g>
+<!-- 6.0 -->
+<g id="node9" class="node">
+<title>6.0</title>
+<g id="a_node9"><a xlink:title="6: 6.0">
+<path fill="white" stroke="none" d="M133.79,-174C133.79,-174 150.21,-174 150.21,-174 155.54,-174 160.88,-179.33 160.88,-184.67 160.88,-184.67 160.88,-195.33 160.88,-195.33 160.88,-200.67 155.54,-206 150.21,-206 150.21,-206 133.79,-206 133.79,-206 128.46,-206 123.12,-200.67 123.12,-195.33 123.12,-195.33 123.12,-184.67 123.12,-184.67 123.12,-179.33 128.46,-174 133.79,-174"/>
+<text text-anchor="start" x="128.12" y="-184.2" font-family="Helvetica,sans-Serif" font-size="14.00">BUS</text>
+<path fill="none" stroke="black" d="M133.79,-174C133.79,-174 150.21,-174 150.21,-174 155.54,-174 160.88,-179.33 160.88,-184.67 160.88,-184.67 160.88,-195.33 160.88,-195.33 160.88,-200.67 155.54,-206 150.21,-206 150.21,-206 133.79,-206 133.79,-206 128.46,-206 123.12,-200.67 123.12,-195.33 123.12,-195.33 123.12,-184.67 123.12,-184.67 123.12,-179.33 128.46,-174 133.79,-174"/>
+</a>
+</g>
+</g>
+</g>
+</svg>


Reviews:
user: login: sampsyo
body: Hi, everybody—thanks for the detailed writeup; this made the adjusted goal and the concrete approach clear. It's too bad that the original plan to use SmoothE did not work out. But it was definitely interesting to see how well ILP-based extraction worked for this workload.

One big question I had was: while I understand how an ILP-based extractor could be an interesting intermediate step, what was your motivation for adding support for good_lp? Were there specific limitations in egg's existing ILP solver support that you needed to work around? It might be nice to add some additional motivation for this in the body of the post.
state: CHANGES_REQUESTED
author_association: OWNER
submitted_at: 2025-05-14T13:10:01Z
user: login: neel-patel-1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T15:30:44Z
user: login: neel-patel-1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T15:30:49Z
user: login: neel-patel-1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T15:47:43Z
user: login: neel-patel-1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T16:17:12Z
user: login: neel-patel-1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T16:18:41Z
user: login: neel-patel-1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T16:19:43Z
user: login: neel-patel-1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T16:55:12Z
user: login: neel-patel-1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T16:55:28Z
user: login: neel-patel-1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T16:56:22Z
user: login: neel-patel-1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T17:03:34Z
user: login: neel-patel-1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T17:04:38Z
user: login: neel-patel-1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T17:32:45Z
user: login: neel-patel-1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T17:34:01Z
user: login: neel-patel-1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T17:35:00Z
user: login: neel-patel-1
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T17:09:34Z

Review comments:
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
path: content/blog/2025-5-13-superopt/index.md
user: login: sampsyo
body: Maybe it would be nice to link to the Wikipedia page, or some other definition? https://en.wikipedia.org/wiki/E-graph
created_at: 2025-05-13T19:51:09Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
path: content/blog/2025-5-13-superopt/index.md
user: login: sampsyo
body: Equality saturation probably also deserves a hyperlink.
created_at: 2025-05-13T19:54:05Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
path: content/blog/2025-5-13-superopt/index.md
user: login: sampsyo
body: "all possible programs" perhaps could use a little more precision here… maybe you mean all the possible results of applying all the rewrite rules?
created_at: 2025-05-13T19:55:03Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
path: content/blog/2025-5-13-superopt/index.md
user: login: sampsyo
body: It seems like a nice idea to use `alt` text, if you can think of anything…
created_at: 2025-05-13T19:55:25Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
path: content/blog/2025-5-13-superopt/index.md
user: login: sampsyo
body: "Technology mapping" is another good place to use a hyperlink to some kind of place where people can learn more.
created_at: 2025-05-13T19:58:31Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
path: content/blog/2025-5-13-superopt/index.md
user: login: sampsyo
body: You mentioned above that egg already has an LP-based exact extractor based on COIN-OR. Can you briefly mention the motivation for switching to good_lp?

Also, do you plan to submit a PR to upstream your good_lp support?
created_at: 2025-05-14T12:55:21Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
path: content/blog/2025-5-13-superopt/index.md
user: login: sampsyo
body: Missing < at the beginning.
created_at: 2025-05-14T12:56:50Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
path: content/blog/2025-5-13-superopt/index.md
user: login: sampsyo
body: verilog -> Verilog
created_at: 2025-05-14T12:57:24Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
+
+Below we give an example of a half-adder written in LutLang:
+
+`(BUS (AND a b) (XOR a b))`
+
+
+### Equality Saturation
+An e-graph representation of the original design using boolean logic, is shown below:
+
+<img src="simple_2_output_before.svg" alt="" width="20%">
+
+The two-input gates are first transformed into programmable LUTs specified by three parameters: a truth table (numeric e-node), and two operands (a and b). During equality saturation, rewrite rules are applied until all possible designs are encoded in the e-graph.
+
+<img src="simple_2_output_lvv_after.svg" alt="" width="33%">
+
+
+### Design Extraction
+
+During extraction, an optimal design is produced using either a greedy or exact (linear programming) method as explained in the [E-graphs and Equality Saturation](#e-graphs-and-equality-saturation) section.
+
+To apply linear programming to the e-graph extraction problem, a set of constraints and objective function must be specified. A number linear-programming libraries implement algorithms to solve linear programming problems. The good\_lp rust crate was developed to make it easier to apply any of the [HiGHs](https://highs.dev/), [SCIP](https://scipopt.org/#scipoptsuite), [microlp](https://github.com/Specy/microlp/), and [COIN-OR Branch-and-Cut](https://github.com/coin-or/Cbc) algorithms to linear programming problems. With good\_lp, the application developer specifies the set of problem variables, a set of constraints, and an objective function to maximize/minimize.  We specify the problem using the formulation of [Yang et al.](https://arxiv.org/pdf/2101.01332). The problem of e-graph extraction can be formalized as follows:
path: content/blog/2025-5-13-superopt/index.md
user: login: sampsyo
body: > A number linear-programming libraries

Maybe missing an "of"?
created_at: 2025-05-14T12:58:24Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
+
+Below we give an example of a half-adder written in LutLang:
+
+`(BUS (AND a b) (XOR a b))`
+
+
+### Equality Saturation
+An e-graph representation of the original design using boolean logic, is shown below:
+
+<img src="simple_2_output_before.svg" alt="" width="20%">
+
+The two-input gates are first transformed into programmable LUTs specified by three parameters: a truth table (numeric e-node), and two operands (a and b). During equality saturation, rewrite rules are applied until all possible designs are encoded in the e-graph.
+
+<img src="simple_2_output_lvv_after.svg" alt="" width="33%">
+
+
+### Design Extraction
+
+During extraction, an optimal design is produced using either a greedy or exact (linear programming) method as explained in the [E-graphs and Equality Saturation](#e-graphs-and-equality-saturation) section.
+
+To apply linear programming to the e-graph extraction problem, a set of constraints and objective function must be specified. A number linear-programming libraries implement algorithms to solve linear programming problems. The good\_lp rust crate was developed to make it easier to apply any of the [HiGHs](https://highs.dev/), [SCIP](https://scipopt.org/#scipoptsuite), [microlp](https://github.com/Specy/microlp/), and [COIN-OR Branch-and-Cut](https://github.com/coin-or/Cbc) algorithms to linear programming problems. With good\_lp, the application developer specifies the set of problem variables, a set of constraints, and an objective function to maximize/minimize.  We specify the problem using the formulation of [Yang et al.](https://arxiv.org/pdf/2101.01332). The problem of e-graph extraction can be formalized as follows:
+
+Let:
+- `i = 0, ..., N - 1` be the set of e-nodes in the e-graph.
+- `m = 0, ..., M - 1` be the set of e-classes in the e-graph.
+- `e_m` denote the set of e-nodes within e-class `m`: `{i | i ∈ e_m}`.
+We introduce a binary integer variable `x_i` for each e-node `i`. A node `i` is selected if `x_i = 1`, and not selected otherwise.
+#### Objective Function:
+Each e-node is associated with a cost `c_i`. The objective is to minimize the total cost of the selected nodes:
+#### Subject to:
+1. `x_i ∈ {0, 1}` for all `i`.
+2. `Σ x_i = 1` for all `i ∈ e_0` (root e-class).
+3. For all `i ∈ h_i` and `m ∈ h_i`, `x_i ≤ Σ x_j` for all `j ∈ e_m`.
+4. Acyclicity constraints: For all `i, m ∈ h_i`, `t_g(i) - t_m - c + A(1 - x_i) ≥ 0`.
+5. Bounds on Acyclicity variables: `0 ≤ t_m ≤ 1`.
+
+good\_lp will transform the problem specification into the implementation-specific data structures and method invocations to solve the problem. By writing our exact extractor using good\_lp, the implementation is agnostic to the solver backend and the problem variables, constraints, and objective function are easy to determine upon inspection.
+
+## Results
+
+We compare the number of LUTs in the designs extracted using greedy and ILP extraction on the [ISCAS85](https://github.com/matth2k/synth-benchmarks/tree/main/verilog/iscas85) design benchmarks. Since finding an exact solution quickly becomes prohibitive in terms of extraction time, (the size of the e-graph and corresponding linear programming problem gets too large), we incrementally increase the number of "rewrite iterations" until reaching 10 . This limits the size of the e-graph by restricting the number of times rewrites are applied. Some benchmarks/solvers were not able to complete even a single iteration within the 30 minute timeout threshold.
path: content/blog/2025-5-13-superopt/index.md
user: login: sampsyo
body: > time, (the size of the e-graph and corresponding linear programming problem gets too large), we

Use commas or parentheses here, but not both.
created_at: 2025-05-14T13:00:02Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
+
+Below we give an example of a half-adder written in LutLang:
+
+`(BUS (AND a b) (XOR a b))`
+
+
+### Equality Saturation
+An e-graph representation of the original design using boolean logic, is shown below:
+
+<img src="simple_2_output_before.svg" alt="" width="20%">
+
+The two-input gates are first transformed into programmable LUTs specified by three parameters: a truth table (numeric e-node), and two operands (a and b). During equality saturation, rewrite rules are applied until all possible designs are encoded in the e-graph.
+
+<img src="simple_2_output_lvv_after.svg" alt="" width="33%">
+
+
+### Design Extraction
+
+During extraction, an optimal design is produced using either a greedy or exact (linear programming) method as explained in the [E-graphs and Equality Saturation](#e-graphs-and-equality-saturation) section.
+
+To apply linear programming to the e-graph extraction problem, a set of constraints and objective function must be specified. A number linear-programming libraries implement algorithms to solve linear programming problems. The good\_lp rust crate was developed to make it easier to apply any of the [HiGHs](https://highs.dev/), [SCIP](https://scipopt.org/#scipoptsuite), [microlp](https://github.com/Specy/microlp/), and [COIN-OR Branch-and-Cut](https://github.com/coin-or/Cbc) algorithms to linear programming problems. With good\_lp, the application developer specifies the set of problem variables, a set of constraints, and an objective function to maximize/minimize.  We specify the problem using the formulation of [Yang et al.](https://arxiv.org/pdf/2101.01332). The problem of e-graph extraction can be formalized as follows:
+
+Let:
+- `i = 0, ..., N - 1` be the set of e-nodes in the e-graph.
+- `m = 0, ..., M - 1` be the set of e-classes in the e-graph.
+- `e_m` denote the set of e-nodes within e-class `m`: `{i | i ∈ e_m}`.
+We introduce a binary integer variable `x_i` for each e-node `i`. A node `i` is selected if `x_i = 1`, and not selected otherwise.
+#### Objective Function:
+Each e-node is associated with a cost `c_i`. The objective is to minimize the total cost of the selected nodes:
+#### Subject to:
+1. `x_i ∈ {0, 1}` for all `i`.
+2. `Σ x_i = 1` for all `i ∈ e_0` (root e-class).
+3. For all `i ∈ h_i` and `m ∈ h_i`, `x_i ≤ Σ x_j` for all `j ∈ e_m`.
+4. Acyclicity constraints: For all `i, m ∈ h_i`, `t_g(i) - t_m - c + A(1 - x_i) ≥ 0`.
+5. Bounds on Acyclicity variables: `0 ≤ t_m ≤ 1`.
+
+good\_lp will transform the problem specification into the implementation-specific data structures and method invocations to solve the problem. By writing our exact extractor using good\_lp, the implementation is agnostic to the solver backend and the problem variables, constraints, and objective function are easy to determine upon inspection.
+
+## Results
+
+We compare the number of LUTs in the designs extracted using greedy and ILP extraction on the [ISCAS85](https://github.com/matth2k/synth-benchmarks/tree/main/verilog/iscas85) design benchmarks. Since finding an exact solution quickly becomes prohibitive in terms of extraction time, (the size of the e-graph and corresponding linear programming problem gets too large), we incrementally increase the number of "rewrite iterations" until reaching 10 . This limits the size of the e-graph by restricting the number of times rewrites are applied. Some benchmarks/solvers were not able to complete even a single iteration within the 30 minute timeout threshold.
+
+| Benchmark | No Optimization LUT Count  | Greedy LUT Count | Microlp LUT Count (# Rewrite Iterations) | Highs LUT Count (# Rewrite Iterations) | CBC LUT Count (# Rewrite Iterations) |
+|-----------|----------------------------|------------------|------------------------------------------|----------------------------------------|---------------------------------------|
+| c1355     | 96                         | 94               | DNF                                      | 96 (10)                                | 96 (5)                                |
+| c17       | 2                          | 2                | 2 (10)                                   | 2 (10)                                 | 2 (10)                                |
+| c1908     | 86                         | 85               | DNF                                      | 84 (8)                                 | 84 (5)                                |
+| c2670     | 120                        | 119              | DNF                                      | 118 (10)                               | DNF                                   |
+| c3540     | 265                        | 260              | DNF                                      | 264 (1)                                | DNF                                   |
+| c432      | 51                         | 50               | DNF                                      | 50 (10)                                | 50 (4)                                |
+| c499      | 90                         | 90               | DNF                                      | 90 (10)                                | 90 (5)                                |
+| c5315     | 267                        | 266              | DNF                                      | 259 (6)                                | DNF                                   |
+| c6288     | 520                        | 512              | DNF                                      | 515 (6)                                | 520 (2)                               |
+| c7552     | 335                        | 325              | DNF                                      | 315 (7)                                | DNF                                   |
+| c880      | DNF                        | DNF              | DNF                                      | DNF                                    | DNF                                   |
+
+The times to solution are reported in the table below
path: content/blog/2025-5-13-superopt/index.md
user: login: sampsyo
body: What units?
created_at: 2025-05-14T13:01:53Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
+
+Below we give an example of a half-adder written in LutLang:
+
+`(BUS (AND a b) (XOR a b))`
+
+
+### Equality Saturation
+An e-graph representation of the original design using boolean logic, is shown below:
+
+<img src="simple_2_output_before.svg" alt="" width="20%">
+
+The two-input gates are first transformed into programmable LUTs specified by three parameters: a truth table (numeric e-node), and two operands (a and b). During equality saturation, rewrite rules are applied until all possible designs are encoded in the e-graph.
+
+<img src="simple_2_output_lvv_after.svg" alt="" width="33%">
+
+
+### Design Extraction
+
+During extraction, an optimal design is produced using either a greedy or exact (linear programming) method as explained in the [E-graphs and Equality Saturation](#e-graphs-and-equality-saturation) section.
+
+To apply linear programming to the e-graph extraction problem, a set of constraints and objective function must be specified. A number linear-programming libraries implement algorithms to solve linear programming problems. The good\_lp rust crate was developed to make it easier to apply any of the [HiGHs](https://highs.dev/), [SCIP](https://scipopt.org/#scipoptsuite), [microlp](https://github.com/Specy/microlp/), and [COIN-OR Branch-and-Cut](https://github.com/coin-or/Cbc) algorithms to linear programming problems. With good\_lp, the application developer specifies the set of problem variables, a set of constraints, and an objective function to maximize/minimize.  We specify the problem using the formulation of [Yang et al.](https://arxiv.org/pdf/2101.01332). The problem of e-graph extraction can be formalized as follows:
+
+Let:
+- `i = 0, ..., N - 1` be the set of e-nodes in the e-graph.
+- `m = 0, ..., M - 1` be the set of e-classes in the e-graph.
+- `e_m` denote the set of e-nodes within e-class `m`: `{i | i ∈ e_m}`.
+We introduce a binary integer variable `x_i` for each e-node `i`. A node `i` is selected if `x_i = 1`, and not selected otherwise.
+#### Objective Function:
+Each e-node is associated with a cost `c_i`. The objective is to minimize the total cost of the selected nodes:
+#### Subject to:
+1. `x_i ∈ {0, 1}` for all `i`.
+2. `Σ x_i = 1` for all `i ∈ e_0` (root e-class).
+3. For all `i ∈ h_i` and `m ∈ h_i`, `x_i ≤ Σ x_j` for all `j ∈ e_m`.
+4. Acyclicity constraints: For all `i, m ∈ h_i`, `t_g(i) - t_m - c + A(1 - x_i) ≥ 0`.
+5. Bounds on Acyclicity variables: `0 ≤ t_m ≤ 1`.
+
+good\_lp will transform the problem specification into the implementation-specific data structures and method invocations to solve the problem. By writing our exact extractor using good\_lp, the implementation is agnostic to the solver backend and the problem variables, constraints, and objective function are easy to determine upon inspection.
+
+## Results
+
+We compare the number of LUTs in the designs extracted using greedy and ILP extraction on the [ISCAS85](https://github.com/matth2k/synth-benchmarks/tree/main/verilog/iscas85) design benchmarks. Since finding an exact solution quickly becomes prohibitive in terms of extraction time, (the size of the e-graph and corresponding linear programming problem gets too large), we incrementally increase the number of "rewrite iterations" until reaching 10 . This limits the size of the e-graph by restricting the number of times rewrites are applied. Some benchmarks/solvers were not able to complete even a single iteration within the 30 minute timeout threshold.
+
+| Benchmark | No Optimization LUT Count  | Greedy LUT Count | Microlp LUT Count (# Rewrite Iterations) | Highs LUT Count (# Rewrite Iterations) | CBC LUT Count (# Rewrite Iterations) |
+|-----------|----------------------------|------------------|------------------------------------------|----------------------------------------|---------------------------------------|
+| c1355     | 96                         | 94               | DNF                                      | 96 (10)                                | 96 (5)                                |
+| c17       | 2                          | 2                | 2 (10)                                   | 2 (10)                                 | 2 (10)                                |
+| c1908     | 86                         | 85               | DNF                                      | 84 (8)                                 | 84 (5)                                |
+| c2670     | 120                        | 119              | DNF                                      | 118 (10)                               | DNF                                   |
+| c3540     | 265                        | 260              | DNF                                      | 264 (1)                                | DNF                                   |
+| c432      | 51                         | 50               | DNF                                      | 50 (10)                                | 50 (4)                                |
+| c499      | 90                         | 90               | DNF                                      | 90 (10)                                | 90 (5)                                |
+| c5315     | 267                        | 266              | DNF                                      | 259 (6)                                | DNF                                   |
+| c6288     | 520                        | 512              | DNF                                      | 515 (6)                                | 520 (2)                               |
+| c7552     | 335                        | 325              | DNF                                      | 315 (7)                                | DNF                                   |
+| c880      | DNF                        | DNF              | DNF                                      | DNF                                    | DNF                                   |
+
+The times to solution are reported in the table below
+
+| Benchmark | Greedy Time       | Microlp Time      | HiGHS Time        | CBC Time           |
+|-----------|-------------------|-------------------|-------------------|--------------------|
+| c1355     | 0.046134086       | DNF               | 640.92384104      | 230.738058229      |
path: content/blog/2025-5-13-superopt/index.md
user: login: sampsyo
body: Please reduce the number of significant figures. For example, it's enough to say that this benchmark using greedy extraction takes 0.05 units (seconds?); we do not need all these decimal digits.
created_at: 2025-05-14T13:02:27Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
+
+Below we give an example of a half-adder written in LutLang:
+
+`(BUS (AND a b) (XOR a b))`
+
+
+### Equality Saturation
+An e-graph representation of the original design using boolean logic, is shown below:
+
+<img src="simple_2_output_before.svg" alt="" width="20%">
+
+The two-input gates are first transformed into programmable LUTs specified by three parameters: a truth table (numeric e-node), and two operands (a and b). During equality saturation, rewrite rules are applied until all possible designs are encoded in the e-graph.
+
+<img src="simple_2_output_lvv_after.svg" alt="" width="33%">
+
+
+### Design Extraction
+
+During extraction, an optimal design is produced using either a greedy or exact (linear programming) method as explained in the [E-graphs and Equality Saturation](#e-graphs-and-equality-saturation) section.
+
+To apply linear programming to the e-graph extraction problem, a set of constraints and objective function must be specified. A number linear-programming libraries implement algorithms to solve linear programming problems. The good\_lp rust crate was developed to make it easier to apply any of the [HiGHs](https://highs.dev/), [SCIP](https://scipopt.org/#scipoptsuite), [microlp](https://github.com/Specy/microlp/), and [COIN-OR Branch-and-Cut](https://github.com/coin-or/Cbc) algorithms to linear programming problems. With good\_lp, the application developer specifies the set of problem variables, a set of constraints, and an objective function to maximize/minimize.  We specify the problem using the formulation of [Yang et al.](https://arxiv.org/pdf/2101.01332). The problem of e-graph extraction can be formalized as follows:
+
+Let:
+- `i = 0, ..., N - 1` be the set of e-nodes in the e-graph.
+- `m = 0, ..., M - 1` be the set of e-classes in the e-graph.
+- `e_m` denote the set of e-nodes within e-class `m`: `{i | i ∈ e_m}`.
+We introduce a binary integer variable `x_i` for each e-node `i`. A node `i` is selected if `x_i = 1`, and not selected otherwise.
+#### Objective Function:
+Each e-node is associated with a cost `c_i`. The objective is to minimize the total cost of the selected nodes:
+#### Subject to:
+1. `x_i ∈ {0, 1}` for all `i`.
+2. `Σ x_i = 1` for all `i ∈ e_0` (root e-class).
+3. For all `i ∈ h_i` and `m ∈ h_i`, `x_i ≤ Σ x_j` for all `j ∈ e_m`.
+4. Acyclicity constraints: For all `i, m ∈ h_i`, `t_g(i) - t_m - c + A(1 - x_i) ≥ 0`.
+5. Bounds on Acyclicity variables: `0 ≤ t_m ≤ 1`.
+
+good\_lp will transform the problem specification into the implementation-specific data structures and method invocations to solve the problem. By writing our exact extractor using good\_lp, the implementation is agnostic to the solver backend and the problem variables, constraints, and objective function are easy to determine upon inspection.
+
+## Results
+
+We compare the number of LUTs in the designs extracted using greedy and ILP extraction on the [ISCAS85](https://github.com/matth2k/synth-benchmarks/tree/main/verilog/iscas85) design benchmarks. Since finding an exact solution quickly becomes prohibitive in terms of extraction time, (the size of the e-graph and corresponding linear programming problem gets too large), we incrementally increase the number of "rewrite iterations" until reaching 10 . This limits the size of the e-graph by restricting the number of times rewrites are applied. Some benchmarks/solvers were not able to complete even a single iteration within the 30 minute timeout threshold.
+
+| Benchmark | No Optimization LUT Count  | Greedy LUT Count | Microlp LUT Count (# Rewrite Iterations) | Highs LUT Count (# Rewrite Iterations) | CBC LUT Count (# Rewrite Iterations) |
+|-----------|----------------------------|------------------|------------------------------------------|----------------------------------------|---------------------------------------|
+| c1355     | 96                         | 94               | DNF                                      | 96 (10)                                | 96 (5)                                |
+| c17       | 2                          | 2                | 2 (10)                                   | 2 (10)                                 | 2 (10)                                |
+| c1908     | 86                         | 85               | DNF                                      | 84 (8)                                 | 84 (5)                                |
+| c2670     | 120                        | 119              | DNF                                      | 118 (10)                               | DNF                                   |
+| c3540     | 265                        | 260              | DNF                                      | 264 (1)                                | DNF                                   |
+| c432      | 51                         | 50               | DNF                                      | 50 (10)                                | 50 (4)                                |
+| c499      | 90                         | 90               | DNF                                      | 90 (10)                                | 90 (5)                                |
+| c5315     | 267                        | 266              | DNF                                      | 259 (6)                                | DNF                                   |
+| c6288     | 520                        | 512              | DNF                                      | 515 (6)                                | 520 (2)                               |
+| c7552     | 335                        | 325              | DNF                                      | 315 (7)                                | DNF                                   |
+| c880      | DNF                        | DNF              | DNF                                      | DNF                                    | DNF                                   |
+
+The times to solution are reported in the table below
+
+| Benchmark | Greedy Time       | Microlp Time      | HiGHS Time        | CBC Time           |
+|-----------|-------------------|-------------------|-------------------|--------------------|
+| c1355     | 0.046134086       | DNF               | 640.92384104      | 230.738058229      |
+| c17       | 0.011094708       | 4.205207809       | 0.00869014        | 0.007125629        |
+| c1908     | 0.03812723        | DNF               | 1551.254409928    | 488.214537225      |
+| c2670     | 0.042055477       | DNF               | 600.226674074     | DNF                |
+| c3540     | 0.032852412       | DNF               | 112.26789725      | DNF                |
+| c432      | 0.022252978       | DNF               | 860.208582938     | 603.27150813       |
+| c499      | 0.023853089       | DNF               | 729.54756512      | 600.49411377       |
+| c5315     | 0.047760014       | DNF               | 743.806362887     | DNF                |
+| c6288     | 0.136245309       | DNF               | 608.710588015     | DNF                |
+| c7552     | 0.045072024       | DNF               | 600.26766583      | DNF                |
+| c880      | DNF               | DNF               | DNF               | DNF                |
+
path: content/blog/2025-5-13-superopt/index.md
user: login: sampsyo
body: For all these results, is there some kind of context you can give to convey whether this is "good" or "bad"? The ideal thing to have done here would be to compare against ABC or similar (on both QoR and running time). But given that it's probably too late to do that, is there any way you could just give some kind of very vague context for how well this system is doing? Are the LUT count reductions anywhere close to the results of traditional tools? How about the running times—is 600 units of time (seconds?) in the ballpark of a traditional tool?
created_at: 2025-05-14T13:04:21Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
+
+Below we give an example of a half-adder written in LutLang:
+
+`(BUS (AND a b) (XOR a b))`
+
+
+### Equality Saturation
+An e-graph representation of the original design using boolean logic, is shown below:
+
+<img src="simple_2_output_before.svg" alt="" width="20%">
+
+The two-input gates are first transformed into programmable LUTs specified by three parameters: a truth table (numeric e-node), and two operands (a and b). During equality saturation, rewrite rules are applied until all possible designs are encoded in the e-graph.
+
+<img src="simple_2_output_lvv_after.svg" alt="" width="33%">
+
+
+### Design Extraction
+
+During extraction, an optimal design is produced using either a greedy or exact (linear programming) method as explained in the [E-graphs and Equality Saturation](#e-graphs-and-equality-saturation) section.
+
+To apply linear programming to the e-graph extraction problem, a set of constraints and objective function must be specified. A number linear-programming libraries implement algorithms to solve linear programming problems. The good\_lp rust crate was developed to make it easier to apply any of the [HiGHs](https://highs.dev/), [SCIP](https://scipopt.org/#scipoptsuite), [microlp](https://github.com/Specy/microlp/), and [COIN-OR Branch-and-Cut](https://github.com/coin-or/Cbc) algorithms to linear programming problems. With good\_lp, the application developer specifies the set of problem variables, a set of constraints, and an objective function to maximize/minimize.  We specify the problem using the formulation of [Yang et al.](https://arxiv.org/pdf/2101.01332). The problem of e-graph extraction can be formalized as follows:
+
+Let:
+- `i = 0, ..., N - 1` be the set of e-nodes in the e-graph.
+- `m = 0, ..., M - 1` be the set of e-classes in the e-graph.
+- `e_m` denote the set of e-nodes within e-class `m`: `{i | i ∈ e_m}`.
+We introduce a binary integer variable `x_i` for each e-node `i`. A node `i` is selected if `x_i = 1`, and not selected otherwise.
+#### Objective Function:
+Each e-node is associated with a cost `c_i`. The objective is to minimize the total cost of the selected nodes:
+#### Subject to:
+1. `x_i ∈ {0, 1}` for all `i`.
+2. `Σ x_i = 1` for all `i ∈ e_0` (root e-class).
+3. For all `i ∈ h_i` and `m ∈ h_i`, `x_i ≤ Σ x_j` for all `j ∈ e_m`.
+4. Acyclicity constraints: For all `i, m ∈ h_i`, `t_g(i) - t_m - c + A(1 - x_i) ≥ 0`.
+5. Bounds on Acyclicity variables: `0 ≤ t_m ≤ 1`.
+
+good\_lp will transform the problem specification into the implementation-specific data structures and method invocations to solve the problem. By writing our exact extractor using good\_lp, the implementation is agnostic to the solver backend and the problem variables, constraints, and objective function are easy to determine upon inspection.
+
+## Results
+
+We compare the number of LUTs in the designs extracted using greedy and ILP extraction on the [ISCAS85](https://github.com/matth2k/synth-benchmarks/tree/main/verilog/iscas85) design benchmarks. Since finding an exact solution quickly becomes prohibitive in terms of extraction time, (the size of the e-graph and corresponding linear programming problem gets too large), we incrementally increase the number of "rewrite iterations" until reaching 10 . This limits the size of the e-graph by restricting the number of times rewrites are applied. Some benchmarks/solvers were not able to complete even a single iteration within the 30 minute timeout threshold.
+
+| Benchmark | No Optimization LUT Count  | Greedy LUT Count | Microlp LUT Count (# Rewrite Iterations) | Highs LUT Count (# Rewrite Iterations) | CBC LUT Count (# Rewrite Iterations) |
+|-----------|----------------------------|------------------|------------------------------------------|----------------------------------------|---------------------------------------|
+| c1355     | 96                         | 94               | DNF                                      | 96 (10)                                | 96 (5)                                |
+| c17       | 2                          | 2                | 2 (10)                                   | 2 (10)                                 | 2 (10)                                |
+| c1908     | 86                         | 85               | DNF                                      | 84 (8)                                 | 84 (5)                                |
+| c2670     | 120                        | 119              | DNF                                      | 118 (10)                               | DNF                                   |
+| c3540     | 265                        | 260              | DNF                                      | 264 (1)                                | DNF                                   |
+| c432      | 51                         | 50               | DNF                                      | 50 (10)                                | 50 (4)                                |
+| c499      | 90                         | 90               | DNF                                      | 90 (10)                                | 90 (5)                                |
+| c5315     | 267                        | 266              | DNF                                      | 259 (6)                                | DNF                                   |
+| c6288     | 520                        | 512              | DNF                                      | 515 (6)                                | 520 (2)                               |
+| c7552     | 335                        | 325              | DNF                                      | 315 (7)                                | DNF                                   |
+| c880      | DNF                        | DNF              | DNF                                      | DNF                                    | DNF                                   |
+
+The times to solution are reported in the table below
+
+| Benchmark | Greedy Time       | Microlp Time      | HiGHS Time        | CBC Time           |
+|-----------|-------------------|-------------------|-------------------|--------------------|
+| c1355     | 0.046134086       | DNF               | 640.92384104      | 230.738058229      |
+| c17       | 0.011094708       | 4.205207809       | 0.00869014        | 0.007125629        |
+| c1908     | 0.03812723        | DNF               | 1551.254409928    | 488.214537225      |
+| c2670     | 0.042055477       | DNF               | 600.226674074     | DNF                |
+| c3540     | 0.032852412       | DNF               | 112.26789725      | DNF                |
+| c432      | 0.022252978       | DNF               | 860.208582938     | 603.27150813       |
+| c499      | 0.023853089       | DNF               | 729.54756512      | 600.49411377       |
+| c5315     | 0.047760014       | DNF               | 743.806362887     | DNF                |
+| c6288     | 0.136245309       | DNF               | 608.710588015     | DNF                |
+| c7552     | 0.045072024       | DNF               | 600.26766583      | DNF                |
+| c880      | DNF               | DNF               | DNF               | DNF                |
+
+*Takeaway:* We observe that there is a scalability, quality tradeoff between greedy and exact extraction. The latter requires orders of magnitude longer time to produce a solution, and can even produce worse solutions when limiting the number of rewrite iterations. As designs scale, it may not be feasible to run exact extraction to find the optimal design.
+
+We also compare the area (µm²) of the designs extracted using greedy and exact extraction (this time only using the top-performing - HiGHs - solver) on the ISCAS85 verilog design benchmarks using a standard cell library. Synthesizing an ASIC design using exact extraction becomes prohibitive faster than synthesis targetting an FPGA due to the larger design search space. There is no "No Optimization" column in this chart. To convert to a standard cell library, a set of rewrite rules must be applied required to convert digital logic to standard cells. We also compare against the Synopsys commercial design compiler to show the design quality a tuned EDA tool can achieve.
+
+| Bench   | Greedy Area   | Exact Area (Node Limit) (msynth) | Synopsys               |
path: content/blog/2025-5-13-superopt/index.md
user: login: sampsyo
body: What does "msynth" mean here?
created_at: 2025-05-14T13:05:19Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
path: content/blog/2025-5-13-superopt/index.md
user: login: neel-patel-1
body: added
created_at: 2025-05-15T15:30:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
path: content/blog/2025-5-13-superopt/index.md
user: login: neel-patel-1
body: fixed
created_at: 2025-05-15T15:30:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
path: content/blog/2025-5-13-superopt/index.md
user: login: neel-patel-1
body: Clarified that "all possible programs resulting from all rewrite rules are encoded in the e-graph"
created_at: 2025-05-15T15:47:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
path: content/blog/2025-5-13-superopt/index.md
user: login: neel-patel-1
body: Descriptions added for each img
created_at: 2025-05-15T16:17:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
path: content/blog/2025-5-13-superopt/index.md
user: login: neel-patel-1
body: added
created_at: 2025-05-15T16:18:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
+
+Below we give an example of a half-adder written in LutLang:
+
+`(BUS (AND a b) (XOR a b))`
+
+
+### Equality Saturation
+An e-graph representation of the original design using boolean logic, is shown below:
+
+<img src="simple_2_output_before.svg" alt="" width="20%">
+
+The two-input gates are first transformed into programmable LUTs specified by three parameters: a truth table (numeric e-node), and two operands (a and b). During equality saturation, rewrite rules are applied until all possible designs are encoded in the e-graph.
+
+<img src="simple_2_output_lvv_after.svg" alt="" width="33%">
+
+
+### Design Extraction
+
+During extraction, an optimal design is produced using either a greedy or exact (linear programming) method as explained in the [E-graphs and Equality Saturation](#e-graphs-and-equality-saturation) section.
+
+To apply linear programming to the e-graph extraction problem, a set of constraints and objective function must be specified. A number linear-programming libraries implement algorithms to solve linear programming problems. The good\_lp rust crate was developed to make it easier to apply any of the [HiGHs](https://highs.dev/), [SCIP](https://scipopt.org/#scipoptsuite), [microlp](https://github.com/Specy/microlp/), and [COIN-OR Branch-and-Cut](https://github.com/coin-or/Cbc) algorithms to linear programming problems. With good\_lp, the application developer specifies the set of problem variables, a set of constraints, and an objective function to maximize/minimize.  We specify the problem using the formulation of [Yang et al.](https://arxiv.org/pdf/2101.01332). The problem of e-graph extraction can be formalized as follows:
+
+Let:
+- `i = 0, ..., N - 1` be the set of e-nodes in the e-graph.
+- `m = 0, ..., M - 1` be the set of e-classes in the e-graph.
+- `e_m` denote the set of e-nodes within e-class `m`: `{i | i ∈ e_m}`.
+We introduce a binary integer variable `x_i` for each e-node `i`. A node `i` is selected if `x_i = 1`, and not selected otherwise.
+#### Objective Function:
+Each e-node is associated with a cost `c_i`. The objective is to minimize the total cost of the selected nodes:
+#### Subject to:
+1. `x_i ∈ {0, 1}` for all `i`.
+2. `Σ x_i = 1` for all `i ∈ e_0` (root e-class).
+3. For all `i ∈ h_i` and `m ∈ h_i`, `x_i ≤ Σ x_j` for all `j ∈ e_m`.
+4. Acyclicity constraints: For all `i, m ∈ h_i`, `t_g(i) - t_m - c + A(1 - x_i) ≥ 0`.
+5. Bounds on Acyclicity variables: `0 ≤ t_m ≤ 1`.
+
+good\_lp will transform the problem specification into the implementation-specific data structures and method invocations to solve the problem. By writing our exact extractor using good\_lp, the implementation is agnostic to the solver backend and the problem variables, constraints, and objective function are easy to determine upon inspection.
+
+## Results
+
+We compare the number of LUTs in the designs extracted using greedy and ILP extraction on the [ISCAS85](https://github.com/matth2k/synth-benchmarks/tree/main/verilog/iscas85) design benchmarks. Since finding an exact solution quickly becomes prohibitive in terms of extraction time, (the size of the e-graph and corresponding linear programming problem gets too large), we incrementally increase the number of "rewrite iterations" until reaching 10 . This limits the size of the e-graph by restricting the number of times rewrites are applied. Some benchmarks/solvers were not able to complete even a single iteration within the 30 minute timeout threshold.
path: content/blog/2025-5-13-superopt/index.md
user: login: neel-patel-1
body: fixed
created_at: 2025-05-15T16:19:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
+
+Below we give an example of a half-adder written in LutLang:
+
+`(BUS (AND a b) (XOR a b))`
+
+
+### Equality Saturation
+An e-graph representation of the original design using boolean logic, is shown below:
+
+<img src="simple_2_output_before.svg" alt="" width="20%">
+
+The two-input gates are first transformed into programmable LUTs specified by three parameters: a truth table (numeric e-node), and two operands (a and b). During equality saturation, rewrite rules are applied until all possible designs are encoded in the e-graph.
+
+<img src="simple_2_output_lvv_after.svg" alt="" width="33%">
+
+
+### Design Extraction
+
+During extraction, an optimal design is produced using either a greedy or exact (linear programming) method as explained in the [E-graphs and Equality Saturation](#e-graphs-and-equality-saturation) section.
+
+To apply linear programming to the e-graph extraction problem, a set of constraints and objective function must be specified. A number linear-programming libraries implement algorithms to solve linear programming problems. The good\_lp rust crate was developed to make it easier to apply any of the [HiGHs](https://highs.dev/), [SCIP](https://scipopt.org/#scipoptsuite), [microlp](https://github.com/Specy/microlp/), and [COIN-OR Branch-and-Cut](https://github.com/coin-or/Cbc) algorithms to linear programming problems. With good\_lp, the application developer specifies the set of problem variables, a set of constraints, and an objective function to maximize/minimize.  We specify the problem using the formulation of [Yang et al.](https://arxiv.org/pdf/2101.01332). The problem of e-graph extraction can be formalized as follows:
+
+Let:
+- `i = 0, ..., N - 1` be the set of e-nodes in the e-graph.
+- `m = 0, ..., M - 1` be the set of e-classes in the e-graph.
+- `e_m` denote the set of e-nodes within e-class `m`: `{i | i ∈ e_m}`.
+We introduce a binary integer variable `x_i` for each e-node `i`. A node `i` is selected if `x_i = 1`, and not selected otherwise.
+#### Objective Function:
+Each e-node is associated with a cost `c_i`. The objective is to minimize the total cost of the selected nodes:
+#### Subject to:
+1. `x_i ∈ {0, 1}` for all `i`.
+2. `Σ x_i = 1` for all `i ∈ e_0` (root e-class).
+3. For all `i ∈ h_i` and `m ∈ h_i`, `x_i ≤ Σ x_j` for all `j ∈ e_m`.
+4. Acyclicity constraints: For all `i, m ∈ h_i`, `t_g(i) - t_m - c + A(1 - x_i) ≥ 0`.
+5. Bounds on Acyclicity variables: `0 ≤ t_m ≤ 1`.
+
+good\_lp will transform the problem specification into the implementation-specific data structures and method invocations to solve the problem. By writing our exact extractor using good\_lp, the implementation is agnostic to the solver backend and the problem variables, constraints, and objective function are easy to determine upon inspection.
+
+## Results
+
+We compare the number of LUTs in the designs extracted using greedy and ILP extraction on the [ISCAS85](https://github.com/matth2k/synth-benchmarks/tree/main/verilog/iscas85) design benchmarks. Since finding an exact solution quickly becomes prohibitive in terms of extraction time, (the size of the e-graph and corresponding linear programming problem gets too large), we incrementally increase the number of "rewrite iterations" until reaching 10 . This limits the size of the e-graph by restricting the number of times rewrites are applied. Some benchmarks/solvers were not able to complete even a single iteration within the 30 minute timeout threshold.
+
+| Benchmark | No Optimization LUT Count  | Greedy LUT Count | Microlp LUT Count (# Rewrite Iterations) | Highs LUT Count (# Rewrite Iterations) | CBC LUT Count (# Rewrite Iterations) |
+|-----------|----------------------------|------------------|------------------------------------------|----------------------------------------|---------------------------------------|
+| c1355     | 96                         | 94               | DNF                                      | 96 (10)                                | 96 (5)                                |
+| c17       | 2                          | 2                | 2 (10)                                   | 2 (10)                                 | 2 (10)                                |
+| c1908     | 86                         | 85               | DNF                                      | 84 (8)                                 | 84 (5)                                |
+| c2670     | 120                        | 119              | DNF                                      | 118 (10)                               | DNF                                   |
+| c3540     | 265                        | 260              | DNF                                      | 264 (1)                                | DNF                                   |
+| c432      | 51                         | 50               | DNF                                      | 50 (10)                                | 50 (4)                                |
+| c499      | 90                         | 90               | DNF                                      | 90 (10)                                | 90 (5)                                |
+| c5315     | 267                        | 266              | DNF                                      | 259 (6)                                | DNF                                   |
+| c6288     | 520                        | 512              | DNF                                      | 515 (6)                                | 520 (2)                               |
+| c7552     | 335                        | 325              | DNF                                      | 315 (7)                                | DNF                                   |
+| c880      | DNF                        | DNF              | DNF                                      | DNF                                    | DNF                                   |
+
+The times to solution are reported in the table below
path: content/blog/2025-5-13-superopt/index.md
user: login: neel-patel-1
body: number of LUTs in the synthesized design  (specified in column headers)
created_at: 2025-05-15T16:55:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
+
+Below we give an example of a half-adder written in LutLang:
+
+`(BUS (AND a b) (XOR a b))`
+
+
+### Equality Saturation
+An e-graph representation of the original design using boolean logic, is shown below:
+
+<img src="simple_2_output_before.svg" alt="" width="20%">
+
+The two-input gates are first transformed into programmable LUTs specified by three parameters: a truth table (numeric e-node), and two operands (a and b). During equality saturation, rewrite rules are applied until all possible designs are encoded in the e-graph.
+
+<img src="simple_2_output_lvv_after.svg" alt="" width="33%">
+
+
+### Design Extraction
+
+During extraction, an optimal design is produced using either a greedy or exact (linear programming) method as explained in the [E-graphs and Equality Saturation](#e-graphs-and-equality-saturation) section.
+
+To apply linear programming to the e-graph extraction problem, a set of constraints and objective function must be specified. A number linear-programming libraries implement algorithms to solve linear programming problems. The good\_lp rust crate was developed to make it easier to apply any of the [HiGHs](https://highs.dev/), [SCIP](https://scipopt.org/#scipoptsuite), [microlp](https://github.com/Specy/microlp/), and [COIN-OR Branch-and-Cut](https://github.com/coin-or/Cbc) algorithms to linear programming problems. With good\_lp, the application developer specifies the set of problem variables, a set of constraints, and an objective function to maximize/minimize.  We specify the problem using the formulation of [Yang et al.](https://arxiv.org/pdf/2101.01332). The problem of e-graph extraction can be formalized as follows:
+
+Let:
+- `i = 0, ..., N - 1` be the set of e-nodes in the e-graph.
+- `m = 0, ..., M - 1` be the set of e-classes in the e-graph.
+- `e_m` denote the set of e-nodes within e-class `m`: `{i | i ∈ e_m}`.
+We introduce a binary integer variable `x_i` for each e-node `i`. A node `i` is selected if `x_i = 1`, and not selected otherwise.
+#### Objective Function:
+Each e-node is associated with a cost `c_i`. The objective is to minimize the total cost of the selected nodes:
+#### Subject to:
+1. `x_i ∈ {0, 1}` for all `i`.
+2. `Σ x_i = 1` for all `i ∈ e_0` (root e-class).
+3. For all `i ∈ h_i` and `m ∈ h_i`, `x_i ≤ Σ x_j` for all `j ∈ e_m`.
+4. Acyclicity constraints: For all `i, m ∈ h_i`, `t_g(i) - t_m - c + A(1 - x_i) ≥ 0`.
+5. Bounds on Acyclicity variables: `0 ≤ t_m ≤ 1`.
+
+good\_lp will transform the problem specification into the implementation-specific data structures and method invocations to solve the problem. By writing our exact extractor using good\_lp, the implementation is agnostic to the solver backend and the problem variables, constraints, and objective function are easy to determine upon inspection.
+
+## Results
+
+We compare the number of LUTs in the designs extracted using greedy and ILP extraction on the [ISCAS85](https://github.com/matth2k/synth-benchmarks/tree/main/verilog/iscas85) design benchmarks. Since finding an exact solution quickly becomes prohibitive in terms of extraction time, (the size of the e-graph and corresponding linear programming problem gets too large), we incrementally increase the number of "rewrite iterations" until reaching 10 . This limits the size of the e-graph by restricting the number of times rewrites are applied. Some benchmarks/solvers were not able to complete even a single iteration within the 30 minute timeout threshold.
+
+| Benchmark | No Optimization LUT Count  | Greedy LUT Count | Microlp LUT Count (# Rewrite Iterations) | Highs LUT Count (# Rewrite Iterations) | CBC LUT Count (# Rewrite Iterations) |
+|-----------|----------------------------|------------------|------------------------------------------|----------------------------------------|---------------------------------------|
+| c1355     | 96                         | 94               | DNF                                      | 96 (10)                                | 96 (5)                                |
+| c17       | 2                          | 2                | 2 (10)                                   | 2 (10)                                 | 2 (10)                                |
+| c1908     | 86                         | 85               | DNF                                      | 84 (8)                                 | 84 (5)                                |
+| c2670     | 120                        | 119              | DNF                                      | 118 (10)                               | DNF                                   |
+| c3540     | 265                        | 260              | DNF                                      | 264 (1)                                | DNF                                   |
+| c432      | 51                         | 50               | DNF                                      | 50 (10)                                | 50 (4)                                |
+| c499      | 90                         | 90               | DNF                                      | 90 (10)                                | 90 (5)                                |
+| c5315     | 267                        | 266              | DNF                                      | 259 (6)                                | DNF                                   |
+| c6288     | 520                        | 512              | DNF                                      | 515 (6)                                | 520 (2)                               |
+| c7552     | 335                        | 325              | DNF                                      | 315 (7)                                | DNF                                   |
+| c880      | DNF                        | DNF              | DNF                                      | DNF                                    | DNF                                   |
+
+The times to solution are reported in the table below
+
+| Benchmark | Greedy Time       | Microlp Time      | HiGHS Time        | CBC Time           |
+|-----------|-------------------|-------------------|-------------------|--------------------|
+| c1355     | 0.046134086       | DNF               | 640.92384104      | 230.738058229      |
path: content/blog/2025-5-13-superopt/index.md
user: login: neel-patel-1
body: fixed
created_at: 2025-05-15T16:55:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
+
+Below we give an example of a half-adder written in LutLang:
+
+`(BUS (AND a b) (XOR a b))`
+
+
+### Equality Saturation
+An e-graph representation of the original design using boolean logic, is shown below:
+
+<img src="simple_2_output_before.svg" alt="" width="20%">
+
+The two-input gates are first transformed into programmable LUTs specified by three parameters: a truth table (numeric e-node), and two operands (a and b). During equality saturation, rewrite rules are applied until all possible designs are encoded in the e-graph.
+
+<img src="simple_2_output_lvv_after.svg" alt="" width="33%">
+
+
+### Design Extraction
+
+During extraction, an optimal design is produced using either a greedy or exact (linear programming) method as explained in the [E-graphs and Equality Saturation](#e-graphs-and-equality-saturation) section.
+
+To apply linear programming to the e-graph extraction problem, a set of constraints and objective function must be specified. A number linear-programming libraries implement algorithms to solve linear programming problems. The good\_lp rust crate was developed to make it easier to apply any of the [HiGHs](https://highs.dev/), [SCIP](https://scipopt.org/#scipoptsuite), [microlp](https://github.com/Specy/microlp/), and [COIN-OR Branch-and-Cut](https://github.com/coin-or/Cbc) algorithms to linear programming problems. With good\_lp, the application developer specifies the set of problem variables, a set of constraints, and an objective function to maximize/minimize.  We specify the problem using the formulation of [Yang et al.](https://arxiv.org/pdf/2101.01332). The problem of e-graph extraction can be formalized as follows:
+
+Let:
+- `i = 0, ..., N - 1` be the set of e-nodes in the e-graph.
+- `m = 0, ..., M - 1` be the set of e-classes in the e-graph.
+- `e_m` denote the set of e-nodes within e-class `m`: `{i | i ∈ e_m}`.
+We introduce a binary integer variable `x_i` for each e-node `i`. A node `i` is selected if `x_i = 1`, and not selected otherwise.
+#### Objective Function:
+Each e-node is associated with a cost `c_i`. The objective is to minimize the total cost of the selected nodes:
+#### Subject to:
+1. `x_i ∈ {0, 1}` for all `i`.
+2. `Σ x_i = 1` for all `i ∈ e_0` (root e-class).
+3. For all `i ∈ h_i` and `m ∈ h_i`, `x_i ≤ Σ x_j` for all `j ∈ e_m`.
+4. Acyclicity constraints: For all `i, m ∈ h_i`, `t_g(i) - t_m - c + A(1 - x_i) ≥ 0`.
+5. Bounds on Acyclicity variables: `0 ≤ t_m ≤ 1`.
+
+good\_lp will transform the problem specification into the implementation-specific data structures and method invocations to solve the problem. By writing our exact extractor using good\_lp, the implementation is agnostic to the solver backend and the problem variables, constraints, and objective function are easy to determine upon inspection.
+
+## Results
+
+We compare the number of LUTs in the designs extracted using greedy and ILP extraction on the [ISCAS85](https://github.com/matth2k/synth-benchmarks/tree/main/verilog/iscas85) design benchmarks. Since finding an exact solution quickly becomes prohibitive in terms of extraction time, (the size of the e-graph and corresponding linear programming problem gets too large), we incrementally increase the number of "rewrite iterations" until reaching 10 . This limits the size of the e-graph by restricting the number of times rewrites are applied. Some benchmarks/solvers were not able to complete even a single iteration within the 30 minute timeout threshold.
+
+| Benchmark | No Optimization LUT Count  | Greedy LUT Count | Microlp LUT Count (# Rewrite Iterations) | Highs LUT Count (# Rewrite Iterations) | CBC LUT Count (# Rewrite Iterations) |
+|-----------|----------------------------|------------------|------------------------------------------|----------------------------------------|---------------------------------------|
+| c1355     | 96                         | 94               | DNF                                      | 96 (10)                                | 96 (5)                                |
+| c17       | 2                          | 2                | 2 (10)                                   | 2 (10)                                 | 2 (10)                                |
+| c1908     | 86                         | 85               | DNF                                      | 84 (8)                                 | 84 (5)                                |
+| c2670     | 120                        | 119              | DNF                                      | 118 (10)                               | DNF                                   |
+| c3540     | 265                        | 260              | DNF                                      | 264 (1)                                | DNF                                   |
+| c432      | 51                         | 50               | DNF                                      | 50 (10)                                | 50 (4)                                |
+| c499      | 90                         | 90               | DNF                                      | 90 (10)                                | 90 (5)                                |
+| c5315     | 267                        | 266              | DNF                                      | 259 (6)                                | DNF                                   |
+| c6288     | 520                        | 512              | DNF                                      | 515 (6)                                | 520 (2)                               |
+| c7552     | 335                        | 325              | DNF                                      | 315 (7)                                | DNF                                   |
+| c880      | DNF                        | DNF              | DNF                                      | DNF                                    | DNF                                   |
+
+The times to solution are reported in the table below
+
+| Benchmark | Greedy Time       | Microlp Time      | HiGHS Time        | CBC Time           |
+|-----------|-------------------|-------------------|-------------------|--------------------|
+| c1355     | 0.046134086       | DNF               | 640.92384104      | 230.738058229      |
+| c17       | 0.011094708       | 4.205207809       | 0.00869014        | 0.007125629        |
+| c1908     | 0.03812723        | DNF               | 1551.254409928    | 488.214537225      |
+| c2670     | 0.042055477       | DNF               | 600.226674074     | DNF                |
+| c3540     | 0.032852412       | DNF               | 112.26789725      | DNF                |
+| c432      | 0.022252978       | DNF               | 860.208582938     | 603.27150813       |
+| c499      | 0.023853089       | DNF               | 729.54756512      | 600.49411377       |
+| c5315     | 0.047760014       | DNF               | 743.806362887     | DNF                |
+| c6288     | 0.136245309       | DNF               | 608.710588015     | DNF                |
+| c7552     | 0.045072024       | DNF               | 600.26766583      | DNF                |
+| c880      | DNF               | DNF               | DNF               | DNF                |
+
path: content/blog/2025-5-13-superopt/index.md
user: login: neel-patel-1
body: I agree. There is still time to rerun with ABC to provide an optimized baseline
created_at: 2025-05-15T16:56:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
+
+Below we give an example of a half-adder written in LutLang:
+
+`(BUS (AND a b) (XOR a b))`
+
+
+### Equality Saturation
+An e-graph representation of the original design using boolean logic, is shown below:
+
+<img src="simple_2_output_before.svg" alt="" width="20%">
+
+The two-input gates are first transformed into programmable LUTs specified by three parameters: a truth table (numeric e-node), and two operands (a and b). During equality saturation, rewrite rules are applied until all possible designs are encoded in the e-graph.
+
+<img src="simple_2_output_lvv_after.svg" alt="" width="33%">
+
+
+### Design Extraction
+
+During extraction, an optimal design is produced using either a greedy or exact (linear programming) method as explained in the [E-graphs and Equality Saturation](#e-graphs-and-equality-saturation) section.
+
+To apply linear programming to the e-graph extraction problem, a set of constraints and objective function must be specified. A number linear-programming libraries implement algorithms to solve linear programming problems. The good\_lp rust crate was developed to make it easier to apply any of the [HiGHs](https://highs.dev/), [SCIP](https://scipopt.org/#scipoptsuite), [microlp](https://github.com/Specy/microlp/), and [COIN-OR Branch-and-Cut](https://github.com/coin-or/Cbc) algorithms to linear programming problems. With good\_lp, the application developer specifies the set of problem variables, a set of constraints, and an objective function to maximize/minimize.  We specify the problem using the formulation of [Yang et al.](https://arxiv.org/pdf/2101.01332). The problem of e-graph extraction can be formalized as follows:
+
+Let:
+- `i = 0, ..., N - 1` be the set of e-nodes in the e-graph.
+- `m = 0, ..., M - 1` be the set of e-classes in the e-graph.
+- `e_m` denote the set of e-nodes within e-class `m`: `{i | i ∈ e_m}`.
+We introduce a binary integer variable `x_i` for each e-node `i`. A node `i` is selected if `x_i = 1`, and not selected otherwise.
+#### Objective Function:
+Each e-node is associated with a cost `c_i`. The objective is to minimize the total cost of the selected nodes:
+#### Subject to:
+1. `x_i ∈ {0, 1}` for all `i`.
+2. `Σ x_i = 1` for all `i ∈ e_0` (root e-class).
+3. For all `i ∈ h_i` and `m ∈ h_i`, `x_i ≤ Σ x_j` for all `j ∈ e_m`.
+4. Acyclicity constraints: For all `i, m ∈ h_i`, `t_g(i) - t_m - c + A(1 - x_i) ≥ 0`.
+5. Bounds on Acyclicity variables: `0 ≤ t_m ≤ 1`.
+
+good\_lp will transform the problem specification into the implementation-specific data structures and method invocations to solve the problem. By writing our exact extractor using good\_lp, the implementation is agnostic to the solver backend and the problem variables, constraints, and objective function are easy to determine upon inspection.
+
+## Results
+
+We compare the number of LUTs in the designs extracted using greedy and ILP extraction on the [ISCAS85](https://github.com/matth2k/synth-benchmarks/tree/main/verilog/iscas85) design benchmarks. Since finding an exact solution quickly becomes prohibitive in terms of extraction time, (the size of the e-graph and corresponding linear programming problem gets too large), we incrementally increase the number of "rewrite iterations" until reaching 10 . This limits the size of the e-graph by restricting the number of times rewrites are applied. Some benchmarks/solvers were not able to complete even a single iteration within the 30 minute timeout threshold.
+
+| Benchmark | No Optimization LUT Count  | Greedy LUT Count | Microlp LUT Count (# Rewrite Iterations) | Highs LUT Count (# Rewrite Iterations) | CBC LUT Count (# Rewrite Iterations) |
+|-----------|----------------------------|------------------|------------------------------------------|----------------------------------------|---------------------------------------|
+| c1355     | 96                         | 94               | DNF                                      | 96 (10)                                | 96 (5)                                |
+| c17       | 2                          | 2                | 2 (10)                                   | 2 (10)                                 | 2 (10)                                |
+| c1908     | 86                         | 85               | DNF                                      | 84 (8)                                 | 84 (5)                                |
+| c2670     | 120                        | 119              | DNF                                      | 118 (10)                               | DNF                                   |
+| c3540     | 265                        | 260              | DNF                                      | 264 (1)                                | DNF                                   |
+| c432      | 51                         | 50               | DNF                                      | 50 (10)                                | 50 (4)                                |
+| c499      | 90                         | 90               | DNF                                      | 90 (10)                                | 90 (5)                                |
+| c5315     | 267                        | 266              | DNF                                      | 259 (6)                                | DNF                                   |
+| c6288     | 520                        | 512              | DNF                                      | 515 (6)                                | 520 (2)                               |
+| c7552     | 335                        | 325              | DNF                                      | 315 (7)                                | DNF                                   |
+| c880      | DNF                        | DNF              | DNF                                      | DNF                                    | DNF                                   |
+
+The times to solution are reported in the table below
+
+| Benchmark | Greedy Time       | Microlp Time      | HiGHS Time        | CBC Time           |
+|-----------|-------------------|-------------------|-------------------|--------------------|
+| c1355     | 0.046134086       | DNF               | 640.92384104      | 230.738058229      |
+| c17       | 0.011094708       | 4.205207809       | 0.00869014        | 0.007125629        |
+| c1908     | 0.03812723        | DNF               | 1551.254409928    | 488.214537225      |
+| c2670     | 0.042055477       | DNF               | 600.226674074     | DNF                |
+| c3540     | 0.032852412       | DNF               | 112.26789725      | DNF                |
+| c432      | 0.022252978       | DNF               | 860.208582938     | 603.27150813       |
+| c499      | 0.023853089       | DNF               | 729.54756512      | 600.49411377       |
+| c5315     | 0.047760014       | DNF               | 743.806362887     | DNF                |
+| c6288     | 0.136245309       | DNF               | 608.710588015     | DNF                |
+| c7552     | 0.045072024       | DNF               | 600.26766583      | DNF                |
+| c880      | DNF               | DNF               | DNF               | DNF                |
+
+*Takeaway:* We observe that there is a scalability, quality tradeoff between greedy and exact extraction. The latter requires orders of magnitude longer time to produce a solution, and can even produce worse solutions when limiting the number of rewrite iterations. As designs scale, it may not be feasible to run exact extraction to find the optimal design.
+
+We also compare the area (µm²) of the designs extracted using greedy and exact extraction (this time only using the top-performing - HiGHs - solver) on the ISCAS85 verilog design benchmarks using a standard cell library. Synthesizing an ASIC design using exact extraction becomes prohibitive faster than synthesis targetting an FPGA due to the larger design search space. There is no "No Optimization" column in this chart. To convert to a standard cell library, a set of rewrite rules must be applied required to convert digital logic to standard cells. We also compare against the Synopsys commercial design compiler to show the design quality a tuned EDA tool can achieve.
+
+| Bench   | Greedy Area   | Exact Area (Node Limit) (msynth) | Synopsys               |
path: content/blog/2025-5-13-superopt/index.md
user: login: neel-patel-1
body: this is actually another tool. similar to lvv, but uses rewrite rules that convert to a standard cell library to target ASICs. clarified in the text: "We use another e-graph-based logic synthesis tool, called msynth, which operates similarly to lvv, but can synthesize ASIC designs using a standard cell library."
created_at: 2025-05-15T17:03:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
+
+Below we give an example of a half-adder written in LutLang:
+
+`(BUS (AND a b) (XOR a b))`
+
+
+### Equality Saturation
+An e-graph representation of the original design using boolean logic, is shown below:
+
+<img src="simple_2_output_before.svg" alt="" width="20%">
+
+The two-input gates are first transformed into programmable LUTs specified by three parameters: a truth table (numeric e-node), and two operands (a and b). During equality saturation, rewrite rules are applied until all possible designs are encoded in the e-graph.
+
+<img src="simple_2_output_lvv_after.svg" alt="" width="33%">
+
+
+### Design Extraction
+
+During extraction, an optimal design is produced using either a greedy or exact (linear programming) method as explained in the [E-graphs and Equality Saturation](#e-graphs-and-equality-saturation) section.
+
+To apply linear programming to the e-graph extraction problem, a set of constraints and objective function must be specified. A number linear-programming libraries implement algorithms to solve linear programming problems. The good\_lp rust crate was developed to make it easier to apply any of the [HiGHs](https://highs.dev/), [SCIP](https://scipopt.org/#scipoptsuite), [microlp](https://github.com/Specy/microlp/), and [COIN-OR Branch-and-Cut](https://github.com/coin-or/Cbc) algorithms to linear programming problems. With good\_lp, the application developer specifies the set of problem variables, a set of constraints, and an objective function to maximize/minimize.  We specify the problem using the formulation of [Yang et al.](https://arxiv.org/pdf/2101.01332). The problem of e-graph extraction can be formalized as follows:
+
+Let:
+- `i = 0, ..., N - 1` be the set of e-nodes in the e-graph.
+- `m = 0, ..., M - 1` be the set of e-classes in the e-graph.
+- `e_m` denote the set of e-nodes within e-class `m`: `{i | i ∈ e_m}`.
+We introduce a binary integer variable `x_i` for each e-node `i`. A node `i` is selected if `x_i = 1`, and not selected otherwise.
+#### Objective Function:
+Each e-node is associated with a cost `c_i`. The objective is to minimize the total cost of the selected nodes:
+#### Subject to:
+1. `x_i ∈ {0, 1}` for all `i`.
+2. `Σ x_i = 1` for all `i ∈ e_0` (root e-class).
+3. For all `i ∈ h_i` and `m ∈ h_i`, `x_i ≤ Σ x_j` for all `j ∈ e_m`.
+4. Acyclicity constraints: For all `i, m ∈ h_i`, `t_g(i) - t_m - c + A(1 - x_i) ≥ 0`.
+5. Bounds on Acyclicity variables: `0 ≤ t_m ≤ 1`.
+
+good\_lp will transform the problem specification into the implementation-specific data structures and method invocations to solve the problem. By writing our exact extractor using good\_lp, the implementation is agnostic to the solver backend and the problem variables, constraints, and objective function are easy to determine upon inspection.
+
+## Results
+
+We compare the number of LUTs in the designs extracted using greedy and ILP extraction on the [ISCAS85](https://github.com/matth2k/synth-benchmarks/tree/main/verilog/iscas85) design benchmarks. Since finding an exact solution quickly becomes prohibitive in terms of extraction time, (the size of the e-graph and corresponding linear programming problem gets too large), we incrementally increase the number of "rewrite iterations" until reaching 10 . This limits the size of the e-graph by restricting the number of times rewrites are applied. Some benchmarks/solvers were not able to complete even a single iteration within the 30 minute timeout threshold.
+
+| Benchmark | No Optimization LUT Count  | Greedy LUT Count | Microlp LUT Count (# Rewrite Iterations) | Highs LUT Count (# Rewrite Iterations) | CBC LUT Count (# Rewrite Iterations) |
+|-----------|----------------------------|------------------|------------------------------------------|----------------------------------------|---------------------------------------|
+| c1355     | 96                         | 94               | DNF                                      | 96 (10)                                | 96 (5)                                |
+| c17       | 2                          | 2                | 2 (10)                                   | 2 (10)                                 | 2 (10)                                |
+| c1908     | 86                         | 85               | DNF                                      | 84 (8)                                 | 84 (5)                                |
+| c2670     | 120                        | 119              | DNF                                      | 118 (10)                               | DNF                                   |
+| c3540     | 265                        | 260              | DNF                                      | 264 (1)                                | DNF                                   |
+| c432      | 51                         | 50               | DNF                                      | 50 (10)                                | 50 (4)                                |
+| c499      | 90                         | 90               | DNF                                      | 90 (10)                                | 90 (5)                                |
+| c5315     | 267                        | 266              | DNF                                      | 259 (6)                                | DNF                                   |
+| c6288     | 520                        | 512              | DNF                                      | 515 (6)                                | 520 (2)                               |
+| c7552     | 335                        | 325              | DNF                                      | 315 (7)                                | DNF                                   |
+| c880      | DNF                        | DNF              | DNF                                      | DNF                                    | DNF                                   |
+
+The times to solution are reported in the table below
+
+| Benchmark | Greedy Time       | Microlp Time      | HiGHS Time        | CBC Time           |
+|-----------|-------------------|-------------------|-------------------|--------------------|
+| c1355     | 0.046134086       | DNF               | 640.92384104      | 230.738058229      |
+| c17       | 0.011094708       | 4.205207809       | 0.00869014        | 0.007125629        |
+| c1908     | 0.03812723        | DNF               | 1551.254409928    | 488.214537225      |
+| c2670     | 0.042055477       | DNF               | 600.226674074     | DNF                |
+| c3540     | 0.032852412       | DNF               | 112.26789725      | DNF                |
+| c432      | 0.022252978       | DNF               | 860.208582938     | 603.27150813       |
+| c499      | 0.023853089       | DNF               | 729.54756512      | 600.49411377       |
+| c5315     | 0.047760014       | DNF               | 743.806362887     | DNF                |
+| c6288     | 0.136245309       | DNF               | 608.710588015     | DNF                |
+| c7552     | 0.045072024       | DNF               | 600.26766583      | DNF                |
+| c880      | DNF               | DNF               | DNF               | DNF                |
+
path: content/blog/2025-5-13-superopt/index.md
user: login: neel-patel-1
body: I will report when this is complete
created_at: 2025-05-15T17:04:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
path: content/blog/2025-5-13-superopt/index.md
user: login: neel-patel-1
body: fixed
created_at: 2025-05-15T17:32:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
path: content/blog/2025-5-13-superopt/index.md
user: login: neel-patel-1
body: fixed throughout
created_at: 2025-05-15T17:34:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
+
+Below we give an example of a half-adder written in LutLang:
+
+`(BUS (AND a b) (XOR a b))`
+
+
+### Equality Saturation
+An e-graph representation of the original design using boolean logic, is shown below:
+
+<img src="simple_2_output_before.svg" alt="" width="20%">
+
+The two-input gates are first transformed into programmable LUTs specified by three parameters: a truth table (numeric e-node), and two operands (a and b). During equality saturation, rewrite rules are applied until all possible designs are encoded in the e-graph.
+
+<img src="simple_2_output_lvv_after.svg" alt="" width="33%">
+
+
+### Design Extraction
+
+During extraction, an optimal design is produced using either a greedy or exact (linear programming) method as explained in the [E-graphs and Equality Saturation](#e-graphs-and-equality-saturation) section.
+
+To apply linear programming to the e-graph extraction problem, a set of constraints and objective function must be specified. A number linear-programming libraries implement algorithms to solve linear programming problems. The good\_lp rust crate was developed to make it easier to apply any of the [HiGHs](https://highs.dev/), [SCIP](https://scipopt.org/#scipoptsuite), [microlp](https://github.com/Specy/microlp/), and [COIN-OR Branch-and-Cut](https://github.com/coin-or/Cbc) algorithms to linear programming problems. With good\_lp, the application developer specifies the set of problem variables, a set of constraints, and an objective function to maximize/minimize.  We specify the problem using the formulation of [Yang et al.](https://arxiv.org/pdf/2101.01332). The problem of e-graph extraction can be formalized as follows:
path: content/blog/2025-5-13-superopt/index.md
user: login: neel-patel-1
body: fixed
created_at: 2025-05-15T17:35:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,183 @@
++++
+title = "Technology Mapping with Egraphs"
+[extra]
+bio = """
+  Arnav Muthiayen is a third year undergraduate student interested in computer architecture.<br>
+  Neel Patel is a first year PhD student interested in computer architecture and systems.<br>
+"""
+[[extra.authors]]
+name = "Arnav Muthiayen"
+[[extra.authors]]
+name = "Neel Patel"
++++
+
+## Introduction
+### E-graphs and Equality Saturation
+Equality-graphs, or more simply, e-graphs, efficiently represent equivalence classes of expressions. This makes them useful for superoptimization, where, given an input program, we seek to find the sequence of optimizations that emits the *best* program, minimizing some user-provided cost function. E-graphs are directed graphs with edges from expressions (*e-nodes* in an e-graph), to a group of e-nodes (an *e-class* in an e-graph, where all the e-nodes contained are equivalent expressions). To efficiently maintain and merge these equivalence classes, e-graphs rely on a union-find data structure. The example below shows an arithmetic expression `a * 2 / 2` represented as an e-graph.
+
+<img src="canonical-example-before.svg" alt="" width="33%">
+
+In *equality saturation*, we apply pattern-based *rewrites* to repeatedly produce equivalent expressions. Each rewrite grows the e-graph, without losing the previous versions of the expression. So if two expressions always evaluate to the same result, they belong in the same e-class. Upon saturation, an e-graph will have undergone enough rewrites to reach a fixed point where it encodes all possible programs simultaneously.
+
+Using the previous example expression, `a * 2 / 2`, three (among many other) rewrite rules can be applied:
+1. Division associativity
+2. Constant folding
+3. Multiplicative identity
+
+As rewrite rules are applied to the expression `a * 2 / 2`, each transformation produces an equivalent form: first rewriting it as `a * (2 / 2)` using division associativity, then simplifying to `a * 1` via constant folding, and finally reducing to `a` using the multiplicative identity. Though the expression changes, all versions are equivalent. It's important to note that applying more rewrite rules, such as multiplicative commutativity or replacing `x * 2` with `x << 1`, doesn’t erase existing expressions. Instead, it expands the e-class by adding more equivalent expressions. The e-graph grows to represent several equivalent expressions, giving the optimizer more options to choose from.
+
+<img src="canonical-example-after.svg" alt="" width="33%">
+
+Equality saturation has found applications in compiler optimization and, recently RTL synthesis. The [E-graphs Good](https://egraphs-good.github.io/) (egg) library provides a fast and extensible implementation of equality saturation, enabling the use of E-graphs in more applications.
+The benefit of equality saturation is that it avoids the problem of finding the optimal order in which to apply optimizations (the phase-ordering problem) by encoding all possible optimizations within the e-graph. The catch is that a separate procedure, called *extraction*, is required to actually select the best term from the e-graph according to a user-provided cost function.
+
+For some simple cost functions, the optimal expression can be found by applying a greedy, bottom-up, extraction procedure, but, in general, the problem of extracting an optimal solution has been shown NP-hard. Currently, Egg implements two extractors.
+The first is a [heuristic greedy extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/extract.rs) which expresses the cost of an e-node as the aggregate cost of its children.
+The second is an [exact extractor](https://github.com/egraphs-good/egg/blob/v0.10.0/src/lp_extract.rs) which formulates extraction as a mixed integer linear programming problem and solves it using the [COIN-OR](https://github.com/coin-or/Cbc) Branch-and-cut solver.
+
+### E-graphs for Technology Mapping
+The task of technology mapping in logic synthesis is to express a given Boolean function as a network of gates from a standard cell library (for ASICs) or programmable LUTs (for FPGAs) so that an objective function, such as total area, is optimized.
+
+Traditional technology mapping tools like [ABC](https://people.eecs.berkeley.edu/~alanmi/abc/) rely on cut enumeration and dynamic programming to select optimal gate implementations. ABC supports both FPGA and ASIC targets and can operate on logic networks with structural choices—precomputed alternative implementations of subcircuits. Its recent addition of a priority-cut-based mapper improves performance by only considering the most promising cuts per node, reducing memory use and runtime. However, the mapper's effectiveness still depends heavily on the initial circuit structure, which may limit optimization potential.
+
+E-graphs offer a more expressive alternative. Rather than selecting cuts locally, they grow a graph of equivalent expressions using rewrite rules. This enables the representation of many circuit topologies simultaneously, effectively enumerating structural choices upfront. After saturation (or a time limit is reached), extraction selects an implementation based on a cost model. Prior work has demonstrated the promise of this approach. [E-Syn](https://arxiv.org/pdf/2403.14242) integrates e-graph rewriting into a delay- and area-aware mapping, showing measurable improvements over standard AIG-based pipelines in delay and area savings. [ROVER](https://ieeexplore.ieee.org/iel8/43/10762795/10549954.pdf) applies e-graphs to RTL datapath optimization and uses ILP-based extraction to achieve up to 63% area savings. These results validate e-graphs as a competitive backend for logic synthesis, capable of exploring larger design spaces than traditional mappers.
+
+### Contributions
+In this project, we integrate multiple linear programming solvers into an e-graph-based electronic design automation (EDA) tool. By using the [good_lp](https://github.com/rust-or/good_lp) library to implement an exact extractor in the [egg](https://github.com/egraphs-good/egg) library, the EDA tool can now use a larger set of solvers. Our good\_lp-based exact extractor is [available](https://github.com/neel-patel-1/egg) and can be used by any projects using the egg library (not just logic synthesis for FPGAs).
+We evaluate the performance of our exact extractor in the context of logic synthesis using the EDA tool, which transforms designs specified in the verilog hardware description language into designs targetting FPGAs or ASICs.
+
+## Optimizing RTL using E-Graphs
+
+### Specifying an RTL Design
+
+For this project, we use an ongoing research compiler in the Zhang research group, called `lvv`. lvv performs optimizations on a domain-specific, circuit-specification language called *LutLang*.
+Here is a rough outline of the grammar defined by LutLang:
+```
+LutLang> ::= <Program> | <Node> | BUS <Node> ... <Node>
+
+<Node> ::= <Const> | x | <Input> | NOR <Node> <Node> | MUX <Node> <Node> <Node>
+            | LUT <Program> <Node> ... <Node> | REG <Node> | ARG <u64> | CYCLE <Node>
+
+<Const> ::= false | true // Base type is a bool
+
+<Input> ::= <String> // Any string is parsed as an input variable
+
+<Program> ::= <u64> // Can store a program for up to 6 bits
+```
+
+lvv takes verilog as input, but converts it into LutLang before performing optimizations and then converts it back into verilog.
+
+Below we give an example of a half-adder written in LutLang:
+
+`(BUS (AND a b) (XOR a b))`
+
+
+### Equality Saturation
+An e-graph representation of the original design using boolean logic, is shown below:
+
+<img src="simple_2_output_before.svg" alt="" width="20%">
+
+The two-input gates are first transformed into programmable LUTs specified by three parameters: a truth table (numeric e-node), and two operands (a and b). During equality saturation, rewrite rules are applied until all possible designs are encoded in the e-graph.
+
+<img src="simple_2_output_lvv_after.svg" alt="" width="33%">
+
+
+### Design Extraction
+
+During extraction, an optimal design is produced using either a greedy or exact (linear programming) method as explained in the [E-graphs and Equality Saturation](#e-graphs-and-equality-saturation) section.
+
+To apply linear programming to the e-graph extraction problem, a set of constraints and objective function must be specified. A number linear-programming libraries implement algorithms to solve linear programming problems. The good\_lp rust crate was developed to make it easier to apply any of the [HiGHs](https://highs.dev/), [SCIP](https://scipopt.org/#scipoptsuite), [microlp](https://github.com/Specy/microlp/), and [COIN-OR Branch-and-Cut](https://github.com/coin-or/Cbc) algorithms to linear programming problems. With good\_lp, the application developer specifies the set of problem variables, a set of constraints, and an objective function to maximize/minimize.  We specify the problem using the formulation of [Yang et al.](https://arxiv.org/pdf/2101.01332). The problem of e-graph extraction can be formalized as follows:
+
+Let:
+- `i = 0, ..., N - 1` be the set of e-nodes in the e-graph.
+- `m = 0, ..., M - 1` be the set of e-classes in the e-graph.
+- `e_m` denote the set of e-nodes within e-class `m`: `{i | i ∈ e_m}`.
+We introduce a binary integer variable `x_i` for each e-node `i`. A node `i` is selected if `x_i = 1`, and not selected otherwise.
+#### Objective Function:
+Each e-node is associated with a cost `c_i`. The objective is to minimize the total cost of the selected nodes:
+#### Subject to:
+1. `x_i ∈ {0, 1}` for all `i`.
+2. `Σ x_i = 1` for all `i ∈ e_0` (root e-class).
+3. For all `i ∈ h_i` and `m ∈ h_i`, `x_i ≤ Σ x_j` for all `j ∈ e_m`.
+4. Acyclicity constraints: For all `i, m ∈ h_i`, `t_g(i) - t_m - c + A(1 - x_i) ≥ 0`.
+5. Bounds on Acyclicity variables: `0 ≤ t_m ≤ 1`.
+
+good\_lp will transform the problem specification into the implementation-specific data structures and method invocations to solve the problem. By writing our exact extractor using good\_lp, the implementation is agnostic to the solver backend and the problem variables, constraints, and objective function are easy to determine upon inspection.
+
+## Results
+
+We compare the number of LUTs in the designs extracted using greedy and ILP extraction on the [ISCAS85](https://github.com/matth2k/synth-benchmarks/tree/main/verilog/iscas85) design benchmarks. Since finding an exact solution quickly becomes prohibitive in terms of extraction time, (the size of the e-graph and corresponding linear programming problem gets too large), we incrementally increase the number of "rewrite iterations" until reaching 10 . This limits the size of the e-graph by restricting the number of times rewrites are applied. Some benchmarks/solvers were not able to complete even a single iteration within the 30 minute timeout threshold.
+
+| Benchmark | No Optimization LUT Count  | Greedy LUT Count | Microlp LUT Count (# Rewrite Iterations) | Highs LUT Count (# Rewrite Iterations) | CBC LUT Count (# Rewrite Iterations) |
+|-----------|----------------------------|------------------|------------------------------------------|----------------------------------------|---------------------------------------|
+| c1355     | 96                         | 94               | DNF                                      | 96 (10)                                | 96 (5)                                |
+| c17       | 2                          | 2                | 2 (10)                                   | 2 (10)                                 | 2 (10)                                |
+| c1908     | 86                         | 85               | DNF                                      | 84 (8)                                 | 84 (5)                                |
+| c2670     | 120                        | 119              | DNF                                      | 118 (10)                               | DNF                                   |
+| c3540     | 265                        | 260              | DNF                                      | 264 (1)                                | DNF                                   |
+| c432      | 51                         | 50               | DNF                                      | 50 (10)                                | 50 (4)                                |
+| c499      | 90                         | 90               | DNF                                      | 90 (10)                                | 90 (5)                                |
+| c5315     | 267                        | 266              | DNF                                      | 259 (6)                                | DNF                                   |
+| c6288     | 520                        | 512              | DNF                                      | 515 (6)                                | 520 (2)                               |
+| c7552     | 335                        | 325              | DNF                                      | 315 (7)                                | DNF                                   |
+| c880      | DNF                        | DNF              | DNF                                      | DNF                                    | DNF                                   |
+
+The times to solution are reported in the table below
+
+| Benchmark | Greedy Time       | Microlp Time      | HiGHS Time        | CBC Time           |
+|-----------|-------------------|-------------------|-------------------|--------------------|
+| c1355     | 0.046134086       | DNF               | 640.92384104      | 230.738058229      |
+| c17       | 0.011094708       | 4.205207809       | 0.00869014        | 0.007125629        |
+| c1908     | 0.03812723        | DNF               | 1551.254409928    | 488.214537225      |
+| c2670     | 0.042055477       | DNF               | 600.226674074     | DNF                |
+| c3540     | 0.032852412       | DNF               | 112.26789725      | DNF                |
+| c432      | 0.022252978       | DNF               | 860.208582938     | 603.27150813       |
+| c499      | 0.023853089       | DNF               | 729.54756512      | 600.49411377       |
+| c5315     | 0.047760014       | DNF               | 743.806362887     | DNF                |
+| c6288     | 0.136245309       | DNF               | 608.710588015     | DNF                |
+| c7552     | 0.045072024       | DNF               | 600.26766583      | DNF                |
+| c880      | DNF               | DNF               | DNF               | DNF                |
+
path: content/blog/2025-5-13-superopt/index.md
user: login: neel-patel-1
body: Since we are using yosys [synth_xilinx](https://yosyshq.readthedocs.io/projects/yosys/en/0.46/cmd/synth_xilinx.html) to synthesize a design targetting an FPGA in all configurations, an ABC tech mapping is always performed. This means that any further LUT decreases in the greedy and exact configurations are *in addition* to the improvements from ABC. This has been clarified in the text and configuration names.


created_at: 2025-05-16T17:09:33Z
author_association: CONTRIBUTOR

PR comments:
user: login: neel-patel-1
created_at: 2025-05-17T05:59:41Z
body: > One big question I had was: while I understand how an ILP-based extractor could be an interesting intermediate step, what was your motivation for adding support for good_lp? Were there specific limitations in egg's existing ILP solver support that you needed to work around? It might be nice to add some additional motivation for this in the body of the post.

This is a reasonable question which deserved further explanation. We added more information to motivate our implementation decision in [Design Extraction](https://github.com/neel-patel-1/cs6120/blob/2025sp/content/blog/2025-5-13-superopt/index.md#design-extraction) in the post.

Briefly, the Coin-OR Branch-and-Cut solver used by egg emits errors for some of the large problems constructed for ASIC synthesis. We hypothesized that the issue had to do with the solver itself, since previous users have also triggered [unexpected behavior](https://github.com/coin-or/Cbc/issues/478) with their problem formulations. We figured we would encounter similar issues with other solvers as well, so being able to quickly switch between them to see if any of them could produce a result would be helpful. In addition, many solvers actually implement different algorithms, so some might be faster than others depending on the problem. This motivated the integration of a good_lp based extractor, which would allow us to quickly switch between solvers at runtime. Also, good_lp provides a clean API for expressing problem variables, constraints and objective function, making it easy to understand the code. Our implementation has drawbacks (performance) as shown in the [Results](https://github.com/neel-patel-1/cs6120/blob/2025sp/content/blog/2025-5-13-superopt/index.md#results) section, though.

author_association: CONTRIBUTOR
user: login: sampsyo
created_at: 2025-05-17T17:11:19Z
body: Got it; that absolutely makes sense!

Thanks for all the changes overall. Can you let me know when I should take another look (and publish) by requesting a review with the widget on the right-hand side of the GitHub PR page?
author_association: OWNER
user: login: neel-patel-1
created_at: 2025-05-17T20:13:55Z
body: I have finished reviewing. Thanks for the feedback on this!
author_association: CONTRIBUTOR
user: login: sampsyo
created_at: 2025-05-18T13:48:07Z
body: Looks great; nice work on this! The expanded detail in the evaluation is especially helpful to see how things worked out.
author_association: OWNER