Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Queues: collect magic numbers, pass 100 commands #1771

Merged
merged 37 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
3c3079e
Oracle for FIFOs
anshumanmohan Nov 7, 2023
ab0408d
Good pseudorandom seed
anshumanmohan Nov 7, 2023
0b1e603
Move two files out of runt's way
anshumanmohan Nov 7, 2023
7a8bbb9
Use new, randomly generated data and expect files for actual testing
anshumanmohan Nov 7, 2023
0cab2c3
Merge branch 'master' into fifo-better-testing
anshumanmohan Nov 7, 2023
d7eca6e
Nits
anshumanmohan Nov 7, 2023
fc6982e
Merge branch 'fifo-better-testing' of https://github.com/cucapra/caly…
anshumanmohan Nov 7, 2023
70a69ee
Generalize fifo_data_gen to all kinds of queues
anshumanmohan Nov 7, 2023
61b43e5
Automatic generation of PIFO data and expect
anshumanmohan Nov 8, 2023
481f818
OO style for FIFO
anshumanmohan Nov 8, 2023
ca732ec
PIFOs in OO style
anshumanmohan Nov 8, 2023
3131c42
Merge branch 'master' into pifo-better-testing
anshumanmohan Nov 8, 2023
1a03b1e
Generalize PIFO to take any two queues
anshumanmohan Nov 8, 2023
5f9ca75
Lift the different queues into their own file
anshumanmohan Nov 8, 2023
d02103c
Lift the runner logic too
anshumanmohan Nov 8, 2023
0b9c600
Tidying
anshumanmohan Nov 8, 2023
8c32e72
Remove stray file
anshumanmohan Nov 8, 2023
84cf9c5
Tidying
anshumanmohan Nov 8, 2023
e388fdb
New data for PIFO tree
anshumanmohan Nov 8, 2023
d29de94
PIFO tree oracle!
anshumanmohan Nov 8, 2023
cf3a9bf
No more ans_mem_len
anshumanmohan Nov 10, 2023
302ee0b
const in one place
anshumanmohan Nov 10, 2023
d0b4db6
Better imports
anshumanmohan Nov 10, 2023
cbe2abb
Rigged random values
anshumanmohan Nov 10, 2023
a0bef3d
Playing with const soem
anshumanmohan Nov 10, 2023
01ad8ae
FIFO works with 100 commands and queue of length 10
anshumanmohan Nov 15, 2023
61eaf49
PIFO and PIFOtree can also handle long lists of commands
anshumanmohan Nov 15, 2023
456ca02
Optional max length of queue
anshumanmohan Nov 15, 2023
359e8ab
Less rigging
anshumanmohan Nov 15, 2023
a85da3b
Less rigging
anshumanmohan Nov 15, 2023
b1fb063
Merge branch 'master' into pifo-better-testing
anshumanmohan Nov 16, 2023
44ba7eb
Merge branch 'pifo-better-testing' into pifotree-better-testing
anshumanmohan Nov 16, 2023
7df6a0f
Merge branch 'master' into pifotree-better-testing
anshumanmohan Nov 16, 2023
5993b39
Merge branch 'pifotree-better-testing' into queues-better-testing
anshumanmohan Nov 16, 2023
b7ec037
Merge branch 'master' into queues-better-testing
anshumanmohan Nov 16, 2023
e7f6717
Update pifotree_oracle.py
anshumanmohan Nov 16, 2023
7c157f2
Newly generated .data and .expect to reverse bad merge
anshumanmohan Nov 16, 2023
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
12 changes: 6 additions & 6 deletions calyx-py/calyx/fifo_oracle.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import queues

import calyx.queues as queues
import calyx.queue_util as queue_util

if __name__ == "__main__":
commands, values = queues.parse_json()
pifo = queues.Fifo([])
ans = queues.operate_queue(commands, values, pifo)
queues.dump_json(commands, values, ans)
commands, values = queue_util.parse_json()
fifo = queues.Fifo([])
ans = queues.operate_queue(commands, values, fifo)
queue_util.dump_json(commands, values, ans)
8 changes: 4 additions & 4 deletions calyx-py/calyx/pifo_oracle.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import queues

import calyx.queues as queues
import calyx.queue_util as queue_util

if __name__ == "__main__":
commands, values = queues.parse_json()
commands, values = queue_util.parse_json()

# Our PIFO is simple: it just orchestrates two FIFOs. The boundary is 200.
pifo = queues.Pifo(queues.Fifo([]), queues.Fifo([]), 200)

ans = queues.operate_queue(commands, values, pifo)
queues.dump_json(commands, values, ans)
queue_util.dump_json(commands, values, ans)
8 changes: 5 additions & 3 deletions calyx-py/calyx/pifotree_oracle.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import queues
import calyx.queues as queues
import calyx.queue_util as queue_util


if __name__ == "__main__":
commands, values = queues.parse_json()
commands, values = queue_util.parse_json()

# Our PIFO is a little complicated: it is a tree of queues.
# The root has two children, which are PIFOs.
Expand All @@ -19,4 +20,5 @@
)

ans = queues.operate_queue(commands, values, pifo)
queues.dump_json(commands, values, ans)
queue_util.dump_json(commands, values, ans)

19 changes: 9 additions & 10 deletions calyx-py/calyx/queue_call.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
# pylint: disable=import-error
import calyx.queue_util as queue_util
import calyx.builder as cb

MAX_CMDS = 15
ANS_MEM_LEN = 10


def insert_main(prog, queue):
"""Inserts the component `main` into the program.
Expand Down Expand Up @@ -33,9 +31,9 @@ def insert_main(prog, queue):
# - one ref register, `ans`, into which the result of a pop or peek is written.
# - one ref register, `err`, which is raised if an error occurs.

commands = main.seq_mem_d1("commands", 2, MAX_CMDS, 32, is_external=True)
values = main.seq_mem_d1("values", 32, MAX_CMDS, 32, is_external=True)
ans_mem = main.seq_mem_d1("ans_mem", 32, 10, 32, is_external=True)
commands = main.seq_mem_d1("commands", 2, queue_util.MAX_CMDS, 32, is_external=True)
values = main.seq_mem_d1("values", 32, queue_util.MAX_CMDS, 32, is_external=True)
ans_mem = main.seq_mem_d1("ans_mem", 32, queue_util.MAX_CMDS, 32, is_external=True)

# The two components we'll use:
queue = main.cell("myqueue", queue)
Expand Down Expand Up @@ -79,10 +77,10 @@ def insert_main(prog, queue):
loop_goes_on
# Does the `err` flag say that the loop should continue?
)
update_i_neq_15, _ = main.neq_store_in_reg(
update_i_neq_max_cmds, _ = main.neq_store_in_reg(
i.out,
cb.const(32, 15),
"i_neq_15",
cb.const(32, queue_util.MAX_CMDS),
"i_neq_max_cmds",
32,
loop_goes_on
# Does the `i` index say that the loop should continue?
Expand Down Expand Up @@ -116,7 +114,8 @@ def insert_main(prog, queue):
],
),
incr_i, # Increment the command index
update_i_neq_15, # Did this increment make us need to break?
update_i_neq_max_cmds,
# Did this increment make us need to break?
],
),
],
Expand Down
27 changes: 15 additions & 12 deletions calyx-py/calyx/queue_data_gen.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import random
import json
from typing import Dict, Union

MAX_CMDS = 15
ANS_MEM_LEN = 10
import calyx.queue_util as queue_util

FormatType = Dict[str, Union[bool, str, int]]

Expand All @@ -17,29 +15,34 @@ def dump_json():
"""Prints a JSON representation of the data to stdout.
The data itself is populated randomly, following certain rules:
- It has three "memories": `commands`, `values`, and `ans_mem`.
- The `commands` memory has MAX_CMDS items, which are 0, 1, or 2.
- The `values` memory has MAX_CMDS items: random values between 0 and 400.
- The `ans_mem` memory has ANS_MEM_LEN items, all zeroes.
- The `commands` memory has queue_util.MAX_CMDS items, which are 0, 1, or 2.
- The `values` memory has queue_util.MAX_CMDS items:
random values between 0 and 400.
- The `ans_mem` memory has queue_util.MAX_CMDS items, all zeroes.
- Each memory has a `format` field, which is a format object for a bitvector.
"""
commands = {
"commands": {
"data": [random.randint(0, 2) for _ in range(MAX_CMDS)],
# The `commands` memory has MAX_CMDS items, which are 0, 1, or 2.
# We'll "rig" these random values a little.
# The first 5% of the commands will be 2 (push).
# The rest will be generated randomly from among 0, 1, and 2.
"data": [2] * (queue_util.MAX_CMDS // 20)
+ [random.randint(0, 2) for _ in range(queue_util.MAX_CMDS * 19 // 20)],
"format": format_gen(2),
}
}
values = {
"values": {
"data": [random.randint(0, 400) for _ in range(MAX_CMDS)],
# The `values` memory has MAX_CMDS items: random values between 0 and 00.
"data": [random.randint(0, 400) for _ in range(queue_util.MAX_CMDS)],
# The `values` memory has queue_util.MAX_CMDS items: random values
# between 0 and 400.
"format": format_gen(32),
}
}
ans_mem = {
"ans_mem": {
"data": [0 for _ in range(ANS_MEM_LEN)],
# The `ans_mem` memory has ANS_MEM_LEN items, all zeroes.
"data": [0 for _ in range(queue_util.MAX_CMDS)],
# The `ans_mem` memory has queue_util.MAX_CMDS items, all zeroes.
"format": format_gen(32),
}
}
Expand Down
29 changes: 29 additions & 0 deletions calyx-py/calyx/queue_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import json
import sys

MAX_CMDS = 100
QUEUE_SIZE = 10


def parse_json():
"""Effectively the opposite of `data_gen`:
Given a JSON file formatted for Calyx purposes, parse it into its two lists:
- The `commands` memory, which has MAX_CMDS items.
- The `values` memory, which has MAX_CMDS items.
Returns the two lists.
"""

data = json.load(sys.stdin)
commands = data["commands"]["data"]
values = data["values"]["data"]
return commands, values


def dump_json(commands, values, ans_mem):
"""Prints a JSON representation of the data to stdout."""
payload = {
"ans_mem": ans_mem,
"commands": commands,
"values": values,
}
print(json.dumps(payload, indent=2))
61 changes: 27 additions & 34 deletions calyx-py/calyx/queues.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import sys
import json
from dataclasses import dataclass
from typing import List

ANS_MEM_LEN = 10
import calyx.queue_util as queue_util


@dataclass
class Fifo:
"""A FIFO data structure.
Supports the operations `push`, `pop`, and `peek`.
Inherent to the queue is its `max_len`, which is given to us at initialization
and we cannot exceed.
"""

def __init__(self, data: List[int]):
def __init__(self, data: List[int], max_len: int = None):
self.data = data
self.max_len = max_len or queue_util.QUEUE_SIZE

def push(self, val: int):
"""Pushes `val` to the FIFO."""
self.data.append(val)
if len(self.data) < self.max_len:
self.data.append(val)
else:
raise IndexError("Cannot push to full FIFO.")

def pop(self) -> int:
"""Pops the FIFO."""
Expand Down Expand Up @@ -49,6 +52,10 @@ class Pifo:
We maintain internally a variable called `pifo_len`:
the sum of the lengths of the two queues.

Inherent to the queue is its `max_len`, which is given to us at initialization
and we cannot exceed.


When asked to pop:
- If `pifo_len` is 0, we raise an error.
- Else, if `hot` is 0, we try to pop from queue_0.
Expand All @@ -64,19 +71,26 @@ class Pifo:
- We don't flip `hot`.

When asked to push:
- If the PIFO is at length `max_len`, we raise an error.
- If the value to be pushed is less than `boundary`, we push it into queue_1.
- Else, we push it into queue_2.
- We increment `pifo_len` by 1.
"""

def __init__(self, queue_1, queue_2, boundary):
def __init__(self, queue_1, queue_2, boundary, max_len=None):
self.data = (queue_1, queue_2)
self.hot = 0
self.pifo_len = len(queue_1) + len(queue_2)
self.boundary = boundary
self.max_len = max_len or queue_util.QUEUE_SIZE
assert (
self.pifo_len <= self.max_len
) # We can't be initialized with a PIFO that is too long.

def push(self, val: int):
"""Pushes `val` to the PIFO."""
if self.pifo_len == self.max_len:
raise IndexError("Cannot push to full PIFO.")
if val < self.boundary:
self.data[0].push(val)
else:
Expand Down Expand Up @@ -120,30 +134,6 @@ def __len__(self) -> int:
return self.pifo_len


def parse_json():
"""Effectively the opposite of `data_gen`:
Given a JSON file formatted for Calyx purposes, parse it into its two lists:
- The `commands` memory, which has MAX_CMDS items.
- The `values` memory, which has MAX_CMDS items.
Returns the two lists.
"""

data = json.load(sys.stdin)
commands = data["commands"]["data"]
values = data["values"]["data"]
return commands, values


def dump_json(commands, values, ans_mem):
"""Prints a JSON representation of the data to stdout."""
payload = {
"ans_mem": ans_mem,
"commands": commands,
"values": values,
}
print(json.dumps(payload, indent=2))


def operate_queue(commands, values, queue):
"""Given the two lists, one of commands and one of values.
Feed these into our queue, and return the answer memory.
Expand All @@ -164,8 +154,11 @@ def operate_queue(commands, values, queue):
break

elif cmd == 2:
queue.push(val)
try:
queue.push(val)
except IndexError:
break

# Pad the answer memory with zeroes until it is of length ANS_MEM_LEN.
ans += [0] * (ANS_MEM_LEN - len(ans))
# Pad the answer memory with zeroes until it is of length MAX_CMDS.
ans += [0] * (queue_util.MAX_CMDS - len(ans))
return ans
Loading
Loading