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

"copy on write" proposal #18

Open
leonardt opened this issue Apr 29, 2019 · 2 comments
Open

"copy on write" proposal #18

leonardt opened this issue Apr 29, 2019 · 2 comments
Assignees

Comments

@leonardt
Copy link
Contributor

It seems like the main issue related to the design of instancing generators it that circuit is a method invoked on generator instances. Basically, this can't be a classmethod because generators are defined as classes with abstract parameters. Generators are instanced with concrete parameter values, which then create definitions. They can also be changed after instantiation (e.g. add ports, wires, children), so circuit is deferred to be called at the final stage once all edits are complete. The challenge here is that even though two generator instances could have the same definition (e.g., they were instanced with the same parameters and no edits were made), in general there is no way to know this fact ahead of time (someone could have made edits to the second instance after instantiation, so we can't assume anything up front).

The proposal is to have instancing generators return singleton object instances based on generator parameter values (__init__ method arguments). Then, calls to circuit can be memoized per instance (so once circuit is invoked on an instance, it is cached for future invocations). Now, when a generator instance is changed (let's say this must be done through pre-defined API methods such as add_ports), this creates a copy of the singleton object (implying a "new" instance of the original generator with "different" parameters). Memoization of the circuit method behaves the same way here (it's done per instance).

The nuance with this approach is w.r.t. to edits that eventually create the same circuit. We could try memoizing based on invocations of API methods, but I have a feeling this complexity might not be a common or high priority issue, so it might be okay to just uniquify this case away in magma for now.

Does this make sense? Are there issues with this approach I'm not considering?

@leonardt
Copy link
Contributor Author

Minor issue is that we can't "return" a new instance when using edit methods (e.g. calling add_port), so this would require the user to invoke a special API like:

my_inst = MyGenerator()
changed_my_inst = my_inst.edit()
# <add ports, children, wires, ...>
changed_my_inst.close()  # Instance can't be changed after

we could use a with pattern here too:

my_inst = MyGenerator()
with my_inst.edit() as new_my_inst:
    # <add ports, children, wires, ...>
    # changed_my_inst.close()  implicit at the end of with block

@Kuree
Copy link
Member

Kuree commented May 3, 2019

What I would suggest is to use a smart hash function that change the generator has everytime an edit is made. For instance

inst0 = MyGenerator()
assert hash(inst0) == 1    # just an example
inst1 = MyGenerator()
assert hash(inst1) == 1    # they are the same circuit
inst0.add_port("a")
assert hash(inst2) == 2   # now it different from inst1

During the circuit generation stage, we will cache the circuit definition based on the hash. Since there is only limited number of operations can be done on a generator, this should be very effective and can be done without changing any existing code. I can think of "change" operations as:

  1. add_port()
  2. remove_port()
  3. wire()
  4. remove_wire()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants