Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyTorch
*.pth
*.pt

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db

# Project specific
*.log
*.out
*.out.dSYM/
gurobi.lp
gurobi.sol
gurobi.log
gurobi_CO.log
gurobi_CO.lp
mytmp.blif
myy.ys
60 changes: 60 additions & 0 deletions ACs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# ACs Directory

This directory contains approximate compressor designs and their metadata.

## Files

### Data Files
- **ac_lib.json**: Library of approximate compressor metadata, including:
- Truth tables for each compressor
- Polynomial expressions for expectations
- Input/output port definitions
- Area and error metrics
- Generated by `extract_lib.py`

### Generated Python Files

#### pairs.py
Auto-generated functions for computing expectations using a **single probability parameter** `p`.
- Each function assumes all inputs have the same probability p of being 1
- Format: `def AC_NAME_S(p): return <polynomial in p>`
- Used by the main training code

#### multi_input_pairs.py
Auto-generated functions with **multiple independent probability parameters** (p1, p2, p3, ...).
- Each input has its own probability parameter
- Parameters correspond to input_ports from ac_lib.json
- Format: `def AC_NAME_S(p1, p2, p3): return <expression>`
- Generated by `generate_multi_input_pairs.py`

### Scripts
- **extract_lib.py**: Generates ac_lib.json and pairs.py from .pla files
- **generate_multi_input_pairs.py**: Generates multi_input_pairs.py from ac_lib.json
- **verify_Compressor.py**: Verification utilities

## Usage

To regenerate the files:
```bash
# Generate ac_lib.json and pairs.py from .pla files
python3 extract_lib.py

# Generate multi_input_pairs.py from ac_lib.json
python3 generate_multi_input_pairs.py
```

## Example

For a 3-input compressor (e.g., AC32_ew1 with inputs x1, x2, x3):

**pairs.py** (single probability):
```python
def AC32_ew1_S(p):
return -p**2 + 2*p
```

**multi_input_pairs.py** (multiple probabilities):
```python
def AC32_ew1_S(p1, p2, p3):
return p1*(1-p2)*(1-p3) + (1-p1)*p2*(1-p3) + ...
```
162 changes: 162 additions & 0 deletions ACs/generate_multi_input_pairs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#!/usr/bin/env python
"""
Generate multi_input_pairs.py from ac_lib.json.
Each function has multiple input parameters (p1, p2, p3, ...)
instead of a single parameter p.
"""
import json
from pathlib import Path

# Configuration
AC_LIB = Path(__file__).parent / "ac_lib.json"
OUT_FILE = Path(__file__).parent / "multi_input_pairs.py"

def generate_expectation_expr(truth_table, input_ports, use_torch=True):
"""
Generate expectation expression from truth table.

Args:
truth_table: List of 0s and 1s for the output
input_ports: List of input port names (e.g., ['x1', 'x2', 'x3'])
use_torch: If True, generate torch expressions, else numpy

Returns:
String expression using p1, p2, p3, etc.
"""
n_inputs = len(input_ports)
terms = []

# Iterate through all possible input combinations
for i in range(2 ** n_inputs):
if truth_table[i] == 0:
continue

# Build term for this input combination
term_factors = []
for bit_idx in range(n_inputs):
bit_val = (i >> bit_idx) & 1
param_name = f"p{bit_idx + 1}"
if bit_val == 1:
term_factors.append(param_name)
else:
term_factors.append(f"(1 - {param_name})")

if term_factors:
term = "*".join(term_factors)
terms.append(term)

if not terms:
if use_torch:
return "torch.zeros_like(p1, device=device)"
else:
return "0*p1"

# Combine all terms
expr = " + ".join(terms)
return expr

def generate_multi_input_pairs():
"""Generate multi_input_pairs.py from ac_lib.json"""

# Load ac_lib.json
with open(AC_LIB, 'r') as f:
lib = json.load(f)

# Start writing output file
with open(OUT_FILE, 'w') as f:
# Write header
f.write("import torch\n\n")
f.write("if torch.cuda.is_available():\n")
f.write(" device = \"cuda\"\n\n")
f.write("elif torch.backends.mps.is_available():\n")
f.write(" device = \"mps\"\n\n")
f.write("else:\n")
f.write(" device = \"cpu\"\n\n")

# Sort AC names for deterministic order
ac_names = sorted(lib.keys())

# Generate functions for each AC
for ac_name in ac_names:
ac = lib[ac_name]
input_ports = ac['input_ports']
n_inputs = len(input_ports)

# Generate parameter list (p1, p2, p3, ...)
param_list = ", ".join([f"p{i+1}" for i in range(n_inputs)])

# Generate S function
truth_s = ac['truth_s']
expr_s = generate_expectation_expr(truth_s, input_ports, use_torch=True)
f.write(f"def {ac_name}_S({param_list}):\n")
f.write(f" return {expr_s}\n\n")

# Generate C function
truth_c = ac['truth_c']
expr_c = generate_expectation_expr(truth_c, input_ports, use_torch=True)
f.write(f"def {ac_name}_C({param_list}):\n")
f.write(f" return {expr_c}\n\n")

# Generate err function (using the MED polynomial from ac_lib)
# We need to convert the error polynomial as well
# For now, let's compute it from truth tables
med_poly = ac.get('med', '0')
if med_poly in ('0', '0.0'):
expr_err = "torch.zeros_like(p1, device=device)"
else:
# Compute error from truth tables
# error = exact - approximate = popcount - (S + 2*C)
error_tt = []
for i in range(2 ** n_inputs):
popcount = bin(i).count('1')
approx = truth_s[i] + 2 * truth_c[i]
error_tt.append(1 if (popcount - approx) > 0 else 0)

# Actually, we need the signed error, so this is more complex
# Let's compute the expectation of (popcount - approx)
error_terms = []
for i in range(2 ** n_inputs):
popcount = bin(i).count('1')
approx = truth_s[i] + 2 * truth_c[i]
err = popcount - approx
if err == 0:
continue

# Build term for this input combination
term_factors = []
for bit_idx in range(n_inputs):
bit_val = (i >> bit_idx) & 1
param_name = f"p{bit_idx + 1}"
if bit_val == 1:
term_factors.append(param_name)
else:
term_factors.append(f"(1 - {param_name})")

if term_factors:
term = "*".join(term_factors)
if err > 0:
error_terms.append(f"{err}*{term}")
else:
error_terms.append(f"({err})*{term}")

if not error_terms:
expr_err = "torch.zeros_like(p1, device=device)"
else:
expr_err = " + ".join(error_terms)

f.write(f"def {ac_name}_err({param_list}):\n")
f.write(f" return {expr_err}\n\n")

# Generate function lists
fn_list_S = ", ".join([f"{ac}_S" for ac in ac_names] + ["lambda p1: p1"])
fn_list_C = ", ".join([f"{ac}_C" for ac in ac_names] + ["lambda p1: 0*p1"])
fn_list_err = ", ".join([f"{ac}_err" for ac in ac_names] + ["lambda p1: 0*p1"])

f.write(f"F_S_LIST = [{fn_list_S}]\n")
f.write(f"F_C_LIST = [{fn_list_C}]\n")
f.write(f"F_ERR_LIST = [{fn_list_err}]\n")

print(f"Generated {OUT_FILE}")

if __name__ == "__main__":
generate_multi_input_pairs()
Loading