How to represent combinational circuits in code - python

I'm writing a python program that does some operations on combinational circuits like comparing for equality to other circuits, merging gates, counting gates, counting connections, finding fanout gates,...
Right now im representing the combinational circuits in the following way:
(I also added the testing for equality)
class Circuit:
def __init__(self):
self.gates = {} # key = the gates number, value = the gate
def __eq__(self, other):
if set(self.gates.keys()) != set(other.gates.keys()):
return False
for key in self.gates.keys():
if self.gates[key] != other.gates[key]:
return False
return True
class Gate:
def __init__(self, gate_type, number):
self.gate_type = gate_type # and, or, nand, nor, xor, xnor
self.number = number
self.incoming_gates = []
self.outgoing_gates = []
def __eq__(self, other):
# i know this is not correct, but in my case correct enough
return (
self.gate_type == other.gate_type
and self.number == other.number
and len(self.incoming) == len(other.incoming)
and len(self.outgoing) == len(other.outgoing)
)
My representation in code seems very laborious to me, so I am looking for a better way to do this. I have searched for best practices on this but didn't find anything.

You're looking to implement a directed graph, with certain data stored in vertices. Wikipedia has a discussion of various ways to represent a graph and here's a stackoverflow talking about the more general problem.
For quickly modifying the topology of the graph, and for doing (merging gates, etc) an adjacency list like you have is often useful.
In general I think the test of an architecture is when you actually start to implement it--I'd suspect you'll become very familiar with the benefits and detriments of your design quickly once you get started using it, and be able to adjust or build helper functions as needed.

You could avoid redundancy in the Gate class by only storing the inbound gate references but that would make the rest of your code more complex to implement. I believe the tradeoff of redundancy vs ease of use should weigh in favour of ease of use.
I don't know how you implement the connections between the gates, but if you hold object references in self.incoming_gates / self.outgoing_gates, you can probably define them based only on incoming links and update the source's outgoing_gate list with self automatically (possibly in the constructor itself)

Related

In LR parsing, is it possible to construct a non-binary AST?

I am currently trying to build a parser for propositional logic using the Python SLY module. SLY is a Python implementation of lex and yacc.
https://sly.readthedocs.io/en/latest/sly.html#introduction
The documentation says, "SLY provides no special functions for constructing an abstract syntax tree. However, such construction is easy enough to do on your own." This is what I am trying to do. In their example code, they recommend doing this by defining your own data structure for tree nodes, and using it in the grammar rules.
class BinOp(Expr):
def __init__(self, op, left, right)
self.op = op
self.left = left
self.right = right
class Number(Expr):
def __init__(self, value):
self.value = value
#_('expr PLUS expr',
'expr MINUS expr',
'expr TIMES expr',
'expr DIVIDE expr')
def expr(self, p):
return BinOp(p[1], p.expr0, p.expr1)
#_('LPAREN expr RPAREN')
def expr(self, p):
return p.expr
My problem is that for my application of parsing propositional logic, although this way of parsing would correctly check syntax and represent the meaning of the logic expression parsed, the parser would construct the AST as a binary tree. Hence, if I were to let it parse the following two expressions:
pvqvr
pv(qvr)
The resulting ASTs would look the same (with right associativity).
For a different part of my project, it is important for me to treat conjunction and disjunction operations as n-ary rather than binary. Taking the first expression above as an example, the disjunction operation is being applied to the three operands p, q, and r simultaneously. I will need to be able to distinguish between the two example expressions above by just looking at the AST itself. The following diagrams show the difference I am going after
v v
/ | \ / \
p q r p v
/ \
q r
Is it theoretically possible with LR parsing to create ASTs with nodes that have more than two children? If so, is the SLY framework robust enough for me to be able to do this, or do I need to create my own parser? If LR parsing is incapable of creating such a tree, are there other algorithms I should consider? I am not doing any further compiling after creating the tree, I just need to form trees that represent propositional logic expressions as indicated above.
Apologies in advance if it's a stupid question, I just took Programming Languages and Translators in the Spring 2020 semester, and with everything that's been going on in the world, the learning experience was rather disruptive. I would greatly appreciate any advice. Thanks so much!
Certainly you can do it. It's just playing around with data structures, after all. However, it's tricky (though certainly not impossible) to cover all the cases while you're parsing, so it may be easier (and more efficient) to transform the tree after the parse is complete.
The key problem is that when you are parsing expr OR expr, it is possible that either or both expr non-terminals are already OR nodes, whose lists need to be combined. So you might start with something like this:
class BinOp(Expr):
def __init__(self, op, left, right)
if left.op == op:
left_ops = left.operands
else:
left_ops = (left,)
if right.op == op:
right_ops = right.operands
else:
right_ops = (right,)
self.op = op
self.operands = left_ops + right_ops
#_('expr OR expr',
'expr AND expr')
def expr(self, p):
return BinOp(p[1], p.expr0, p.expr1)
That will work. But here's my suspicion (because it's happened to me, over and over again with different variations): at some point you'll want to apply deMorgan's laws (perhaps not consistently, but in some cases), so you'll end up turning some negated conjunction nodes into disjunctions and/or negated disjunction nodes in conjunctions. And after you do that, you'll want to compress the new disjunction (or conjunction nodes) again, because otherwise your newly created nodes may violate the constraint that the operands of a conjunction/disjuntion operator cannot be conjunctions/disjunctions (respectively). And as you crawl through the tree applying deMorgan, you might end up doing various flips which require more compression passes...
So my hunch is that you'll find yourself with less repetitive code and a clearer control flow if you first parse (which often naturally produces binary trees) and then do the various transformations you in an appropriate order.
Nonetheless, there are certainly grammars which naturally produce multivalent nodes rather than binary nodes; the classic one is argument lists, but any list structure will have the same effect. Here, the list is (probably) not the result of flattening parenthetic subexpressions, though. It simply responds to a grammar such as:
#_('expr')
def exprlist(self, p):
return [p.expr]
#_('exprlist "," expr')
def exprlist(self, p):
p.exprlist.append(p.expr)
return p.exprlist
#_('ID "(" exprlist ")" ')
def expr(self, p):
return ('call', p.ID, p.exprlist)
# Or, if you want a truly multivalent node:
# return ('call', p.ID) + tuple(p.exprlist)
SLY can do that sort of thing automatically if you give it EBNF productions, so that might only be slightly interesting.

How can I improve the runtime of Python implementation of cycle detection in Course Schedule problem?

My aim is to improve the speed of my Python code that has been successfully accepted in a leetcode problem, Course Schedule.
I am aware of the algorithm but even though I am using O(1) data-structures, my runtime is still poor: around 200ms.
My code uses dictionaries and sets:
from collections import defaultdict
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
course_list = []
pre_req_mapping = defaultdict(list)
visited = set()
stack = set()
def dfs(course):
if course in stack:
return False
stack.add(course)
visited.add(course)
for neighbor in pre_req_mapping.get(course, []):
if neighbor in visited:
no_cycle = dfs(neighbor)
if not no_cycle:
return False
stack.remove(course)
return True
# for course in range(numCourses):
# course_list.append(course)
for pair in prerequisites:
pre_req_mapping[pair[1]].append(pair[0])
for course in range(numCourses):
if course in visited:
continue
no_cycle = dfs(course)
if not no_cycle:
return False
return True
What else can I do to improve the speed?
You are calling dfs() for a given course multiple times.
But its return value won't change.
So we have an opportunity to memoize it.
Change your algorithmic approach (here, to dynamic programming)
for the big win.
It's a space vs time tradeoff.
EDIT:
Hmmm, you are already memoizing most of the computation
with visited, so lru_cache would mostly improve clarity
rather than runtime.
It's just a familiar idiom for caching a result.
It would be helpful to add a # comment citing a reference
for the algorithm you implemented.
This is a very nice expression, with defaulting:
pre_req_mapping.get(course, [])
If you use timeit you may find that the generated bytecode
for an empty tuple () is a tiny bit more efficient than that
for an empty list [], as it involves fewer allocations.
Ok, some style nits follow, unrelated to runtime.
As an aside, youAreMixingCamelCase and_snake_case.
PEP-8 asks you to please stick with just snake_case.
This is a fine choice of identifier name:
for pair in prerequisites:
But instead of the cryptic [0], [1] dereferences,
it would be easier to read a tuple unpack:
for course, prereq in prerequisites:
if not no_cycle: is clumsy.
Consider inverting the meaning of dfs' return value,
or rephrasing the assignment as:
cycle = not dfs(course)
I think that you are doing it in good way, but since Python is an interpreted language, it's normal to have slow runtime compared with compiled languages like C/C++ and Java, especially for large inputs.
Try to write the same code in C/C++ for example and compare the speed between them.

How to brute force a tree of 'yes/no' decisions?

I want to solve a puzzle. But I simply don't know what kind of code is required for it. The problem is an exponential one.
Description:
The Player walks/runs one step at a time. Sometimes there will be a decision to be made; that is a yes/no question. Once the question is answered, the player continues walking until the next decision/question is reached. Continue this until the total distance is covered.
The problem is I want to see every possible route through this (many python lists such as ['y','y','n','y','n']). Here is the code I have written so far: (the Player is in a Player() class, I have removed it because it is unimportant here.)
class Solver(object):
""" Solver object. """
def __init__(self, field):
self.field = field
self.dinc = 113
self.distance = 128
def take_step(self, player):
""" Takes a step and records players route. """
# Adds 0 if there is no decision to be made on this step
# Adds 1 if there is a decision to be made on this step
player.run(self.dinc)
if self._is_decision_time(player):
player.route.append((player.step_id, 1))
else:
player.route.append((player.step_id, 0))
def next_decision(self, player):
""" Accepts a player object. Walks until reaches next decision. """
while not self._is_decision_time(player):
self.take_step(player)
self.display_stats(player)
def say_no(self, player):
""" Simulates a no response. Resets danger. Updates route with decision. """
player.route[-1] = (player.step_id, 'n')
player.danger = 0
print 'no!'
def say_yes(self, player):
""" Simulates a yes response. Updates route with decision. """
player.route[-1] = (player.step_id, 'y')
print 'yes!'
The solution of what I'm looking for is like this:
Walk until a question is reached
Make a copy of the route
On route A say Yes
On route B (the copy) say No
Route A:
repeat what is above (this forks another two routes)
Route B:
repeat what is above (this forks another two routes)
Using the code I have so far, it is something like:
route_a = Player()
solver = Solver()
# walk until a battle is reached
solver.next_decision(route_a)
# make a copy of the route (there are now two routes A + route B)
route_b = copy.deepcopy(route_a)
# on route A say 'yes'
solver.say_yes(route_a)
# on route B say 'no'
solver.say_no(route_b)
# walk until the next decision is reached
solver.next_battle(route_a)
solver.next_battle(route_b)
# Then?
This problem is exponential, because at each decision the route forks into two more routes. I need all of the possibilities; I happen to know there are less than 512 possibilities so a computer can solve it in an instant.
Each route will be stored in a Player.route instance (as a list, eg: ['y','y','n','y'])
I just have no idea how to solve a problem like this programmatically. I would appreciate some ideas as to how to structure code to solve a problem like this.
Actually, such a data structure -- a binary tree -- is used in order to just avoid the exponential problem you mentioned. Or, in other words, the supposed list of 'y' and 'n' will grow exponentially, but usually you don't need it, because you have the binary tree. You know that you get each way by a yes-or-no question.
But, if you want to print the list you were asking for, do it like in this pseudo-code (since I'm lost to C++, I still can't program in Python ;-) )
def recurse(node, s=''):
if node == end_node:
print s
return
recurse(node.left, s + 'n')
recurse(node.right, s + 'y')
Then invoke the function starting at the root or head node, i.e. recurse(root_node).
This seems like a fairly easy job for recursion and you already have a pretty simple tree structure. Perhaps you should just migrate the decision process into an explicit tree structure and implement a recursive traversal of the nodes? That's probably the most prudent solution given what it looks like you're trying to do. I guess you're looking for "brute force"... but the alternate iterative solution would be a lot less elegant (and harder to write).
A naive, but probably a suitable way to generate permutations like this is to run through numbers 0..512, convert them to binary (with right padding) and treat zeroes as 'No' and ones as 'Yes'. Nine bits is enough for 512 values, so generate a string like this:
'{0:0>9b}'.format(123)

User-defined Vector class for python

I've been looking for a way to deal with vectors in python and havent found a solution here or in the documentation that completely fits me.
This is what I've come up with so far for a vector class:
class vec(tuple):
def __add__(self, y):
if len(self)!=len(y):
raise TypeError
else:
ret=[]
for i,entry in enumerate(self):
ret.append(entry+y[i])
return vec(ret)
def __mul__(self, y):
t=y.__class__
if t == int or t==float:
#scalar multiplication
ret=[]
for entry in self:
ret.append(y*entry)
return vec(ret)
elif t== list or t==tuple or t==vec:
# dot product
if len(y)!=len(self):
print 'vecs dimensions dont fit'
raise TypeError
else:
ret=0
for i,entry in enumerate(self):
ret+=entry*y[i]
return ret
Theres a little bit more, left out to keep things short.
So far everythings working fine but I have lots of tiny specific questions (and will probably post more as they come up):
Are there base classes for the numeric and sequence-types and how can I address them?
How can I make all of this more Python-y? I want to learn how to write good Python code, so if you find something that's inefficient or just ugly, please tell me.
What about precision? As python seems to cast from integers to floats only if necessary, input and output are usually of the same type. So there might be problems with very large or small numbers, but I don't really need those currently. Should I generally worry about precision or does python do that for me? Would it be better to convert to the largest possible type automatically? Which one is that? What happens beyond that?
I want to use n-dimensional vectors in a project involving lots of vectorial equations and functions and I'd like to be able to use the usual notation that's used in math textbooks. As you can see this inherits from tuple (for easy construction, immutability and indexing) and most built in functions are overwritten in order to use the (+,-,*,..)- operators. They only work if the left operand is a vec (can I change that?). Multiplication includes dot- and scalar product, pow is also used for the cross-product if both vecs are 3D.
Test Script:
def testVec():
rnd=random.Random()
for i in range(0,10000):
a=utils.vec((rnd.random(),rnd.random(),rnd.random()))
### functions to test
a*(a*a)
###
def testNumpy():
rnd=random.Random()
for i in range(0,10000):
a=np.array((rnd.random(),rnd.random(),rnd.random()))
###
a.dot(a)*a
###
cProfile.run('testNumpy()')
-> 50009 function calls in 0.135 seconds
cProfile.run('testVec()')
-> 100009 function calls in 0.064 seconds

Where to put the separation between a stateful object and a stateless calculation in Python?

Which of the following code snippets is the most "pythonic"? The calculation is trivial in this example but could be assumed to be complex in real life.
class A(object):
"""Freely mix state and calcs - no good I presume"""
def __init__(self, state):
self.state = state
def calc_with_state(self, x):
return (self.state + x)**2
or
class B(object):
"""Separate state from calc by a static method"""
#staticmethod
def inner_calc(u, v):
return (u + v)**2
def __init__(self, state):
self.state = state
def calc_with_state(self, x):
return B.inner_calc(self.state, x)
or
class C(object):
"""Break out the calculation in a free function"""
def __init__(self, state):
self.state = state
def calc_with_state(self, x):
return outer_calc(self.state, x)
def outer_calc(u, v):
return (u + v)**2
As written, A, by a longshot. The issue, quite simply, is
Flat is better than nested.
Look: separating state from calculations is a good design principle, but it doesn't mean what you think, at least not what I can infer you think from this example. We want to make sure that state doesn't change in order to complete calculations if that state isn't going to be reinitialized on the next calculation. If state is read-only with respect to some particular calculation, there's no stylistic compulsion to redirect around it so that you don't directly read it. That is, unless the calculation and the state are sufficiently complex to need separate unit testing. Then, by all means, B or C will be preferred, but only if it is really that much easier to create values for u than to instantiate fresh instances of A.
I think it depends on your particular project. Is cal_with_state only applicable to this particular class or is the method needs to be shared among many different objects? Do different classes share it?
There is nothing more or less pythonic about any of this approaches, use the one that will satisfy your project. DRY is beyond pythonicity.
Factoring out the calculation, whether in a static or global method doesn't offer any benefit with regards to the state awareness. The only slight advantage is that the code explicitly shows which of the object's stateful properties are taken into account in the calculation (show at the level of the function call, rather than having to be read within the logic of the method in the class A)
There may be other advantages to introducing stateless (static, global) or instance methods:
reusability
code readability and management at large
but as said, these constructs do not help with regards to state management per-se. The A approach seems quite legitimate (and pythonic) to me. Indeed David Berger beat us to it, in reminding us that...
Flat is better than nested! .
Personally I would say it depends on resusability. If the calculation is one that might be used with other objects (as it does look to be) then the third example is the most reusable. If the calculation is completely tied to the object or would never be reused then the first example. I'd say the second example is wrong in most cases.
What is wrong with A? It does the calculation in one place only and does not modify the state so calc_with_state is a method that does not change state so is a 'simple' behaviour. If the state was complex it stops a large number of parameters being passed into the calculation function.
However if the calculation can be written taking the state as a parameter (as in C) then you can separate out the calculation. benefits here include being able to rues this calculation on data not in the class C and also you can use the function as data passed to C so calc_with_state can be made to call different calculation functions
I can't see B having any benefits as inner_calc does not make use of the class and so could just as well be a free function.
So I would probably write it as A first and then if wanting to reuse the calculation, make the class use different calculations or just if the code of the calculation got too big you could refactor into class C

Categories