def test_remove(self): expr = boolean.parse("a*b*c") p1 = boolean.parse("b*d") p2 = boolean.parse("a*c") result = boolean.parse("b") self.assertTrue(expr.remove(p1) == expr) self.assertTrue(expr.remove(p2) == result)
def test_or(self): expr = boolean.Symbol("A") + boolean.Symbol("B") plus = boolean.parse("A+B") l_or = boolean.parse("A∨B") self.assertEqual(expr, plus) self.assertEqual(expr, l_or)
def test_simplify(self): a = boolean.Symbol("a") self.assertTrue(~a == ~a) self.assertFalse(a == boolean.parse("~~a", simplify=False)) self.assertTrue(a == ~~a) self.assertTrue(~a == ~~~a) self.assertTrue(a == ~~~~a) self.assertTrue(~(a * a * a) == ~(a * a * a)) self.assertFalse(a == boolean.parse("~ ~a", simplify=False))
def test_not(self): expr = ~boolean.Symbol("A") prime = boolean.parse("A'") tilde = boolean.parse("~A") l_not = boolean.parse("¬A") p_not = boolean.parse("!A") self.assertEqual(expr, prime) self.assertEqual(expr, tilde) self.assertEqual(expr, l_not) self.assertEqual(expr, p_not)
def test_class_order(self): order = ((boolean.TRUE, boolean.FALSE), (boolean.Symbol(), boolean.Symbol("x")), (boolean.parse("x*y"),), (boolean.parse("x+y"),), ) for i, tests in enumerate(order): for case1 in tests: for j in range(i + 1, len(order)): for case2 in order[j]: self.assertTrue(case1 < case2) self.assertTrue(case2 > case1)
def test_and(self): expr = boolean.Symbol("A") * boolean.Symbol("B") star = boolean.parse("A*B") dot = boolean.parse("A∙B") decimal = boolean.parse("A.B") hat = boolean.parse("A^B") l_and = boolean.parse("A∧B") self.assertEqual(expr, star) self.assertEqual(expr, dot) self.assertEqual(expr, decimal) self.assertEqual(expr, hat) self.assertEqual(expr, l_and)
def test_class_order(self): order = ( (boolean.TRUE, boolean.FALSE), (boolean.Symbol(), boolean.Symbol("x")), (boolean.parse("x*y"), ), (boolean.parse("x+y"), ), ) for i, tests in enumerate(order): for case1 in tests: for j in range(i + 1, len(order)): for case2 in order[j]: self.assertTrue(case1 < case2) self.assertTrue(case2 > case1)
def test_demorgan(self): a, b = boolean.symbols("a", "b") parse = lambda x: boolean.parse(x, simplify=False) self.assertTrue(parse("~(a*b)").demorgan() == ~a + ~b) self.assertTrue(parse("~(a+b+c)").demorgan() == parse("~a*~b*~c")) self.assertTrue(parse("~(~a*b)").demorgan() == a + ~b)
def test_cancel(self): a = boolean.Symbol("a") parse = lambda x: boolean.parse(x, simplify=False) self.assertTrue(~a == (~a).cancel()) self.assertTrue(a == parse("~~a").cancel()) self.assertTrue(~a == parse("~~~a").cancel()) self.assertTrue(a == parse("~~~~a").cancel())
def test_printing(self): a = boolean.Symbol("a") self.assertTrue(str(~a) == "~a") self.assertTrue(repr(~a) == "NOT(Symbol('a'))") expr = boolean.parse("~(a*a)", simplify=False) self.assertTrue(str(expr) == "~(a*a)") self.assertTrue(repr(expr) == "NOT(AND(Symbol('a'), Symbol('a')))")
def test_cancel(self): a = boolean.Symbol("a") parse = lambda x: boolean.parse(x, eval=False) self.assertTrue(~a == (~a).cancel()) self.assertTrue(a == parse("~~a").cancel()) self.assertTrue(~a == parse("~~~a").cancel()) self.assertTrue(a == parse("~~~~a").cancel())
def __init__(self, pos, dual_expression, hidden=False, anonymous_symbols=True): if isinstance(dual_expression, str): dual_expression = boolean.parse(dual_expression) if not isinstance(dual_expression, boolean.Function): raise TypeError("Argument must be str or Function but it is {}" .format(dual_expression.__class__)) if len(dual_expression.symbols) != 2: raise ValueError("Argument must only contain two symbols but contains {}" .format(len(dual_expression.symbols))) component = logic_circuit.Gate(dual_expression, anonymous_symbols=anonymous_symbols) super().__init__(pos, hidden, component) input_symbols = tuple(k for k, v in self.component.inputs.items()) # Comments are the maths behind the ratio for where the inputs are # (30.939-(22.482+0.825/2))*self.h/30.939 top_input_y = int(0.260012 * self.h) # (30.939-(7.633+0.825/2))*self.h/30.939 botton_input_y = math.ceil(0.739956 * self.h) self.inputs[(SELECT_RADIUS, top_input_y)] = input_symbols[0] self.inputs[(SELECT_RADIUS, botton_input_y)] = input_symbols[1]
def test_printing(self): a = boolean.Symbol("a") self.assertTrue(str(~a) == "a'") self.assertTrue(repr(~a) == "NOT(Symbol('a'))") expr = boolean.parse("~(a*a)", eval=False) self.assertTrue(str(expr) == "(a∙a)'") self.assertTrue(repr(expr) == "NOT(AND(Symbol('a'), Symbol('a')))")
def test_subs(self): a, b, c = boolean.symbols("a", "b", "c") expr = a * b + c self.assertEqual(expr.subs({a: b}), b + c) self.assertEqual(expr.subs({a: a}), expr) self.assertEqual(expr.subs({a: b + c}), boolean.parse("(b+c)*b+c")) self.assertEqual(expr.subs({a * b: a}), a + c) self.assertEqual(expr.subs({c: boolean.TRUE}), boolean.TRUE)
def expression(self, expression): if isinstance(expression, str): expression = boolean.parse(expression, False) if not isinstance(expression, boolean.Expression): raise TypeError( "Argument must be str or Expression but it is {}".format( expression.__class__)) return expression
def test_eval(self): a = boolean.Symbol("a") self.assertTrue(~a == ~a) self.assertFalse(a == boolean.parse("~~a", eval=False)) self.assertTrue(a == ~~a) self.assertTrue(~a, ~~~a) self.assertTrue(a, ~~~~a) self.assertTrue(~(a * a * a) == ~(a * a * a))
def test_printing(self): parse = lambda x: boolean.parse(x, simplify=False) self.assertTrue(str(parse("a*a")) == "a*a") self.assertTrue(repr(parse("a*a")) == "AND(Symbol('a'), Symbol('a'))") self.assertTrue(str(parse("a+a")) == "a+a") self.assertTrue(repr(parse("a+a")) == "OR(Symbol('a'), Symbol('a'))") self.assertTrue(str(parse("(a+b)*c")) == "(a+b)*c") self.assertTrue(repr(parse("(a+b)*c")) == "AND(OR(Symbol('a'), Symbol('b')), Symbol('c'))")
def test_creation(self): E = boolean.Expression expr_str = "(a+b+c)*d*(~e+(f*g))" expr = boolean.parse(expr_str) self.assertTrue(E(expr) is expr) self.assertTrue(E(expr_str) == expr) self.assertTrue(E(1) is boolean.TRUE) self.assertTrue(E(True) is boolean.TRUE) self.assertTrue(E(0) is boolean.FALSE) self.assertTrue(E(False) is boolean.FALSE)
def test_literals(self): a = boolean.Symbol("a") l = ~a self.assertTrue(l.isliteral) self.assertTrue(l in l.literals) self.assertTrue(len(l.literals) == 1) l = boolean.parse("~(a*a)", simplify=False) self.assertFalse(l.isliteral) self.assertTrue(a in l.literals) self.assertTrue(len(l.literals) == 1)
def table(self, table): if isinstance(table, str): table = boolean.parse(table, False) if isinstance(table, boolean.Expression): table = boolean.truth_table(table) else: raise TypeError("Argument must be Expression but it is {}".format( table.__class__)) # Table should not be directly modified return tuple(table)
def test_literals(self): a = boolean.Symbol("a") l = ~a self.assertTrue(l.isliteral) self.assertTrue(l in l.literals) self.assertTrue(len(l.literals) == 1) l = boolean.parse("~(a*a)", eval=False) self.assertFalse(l.isliteral) self.assertTrue(a in l.literals) self.assertTrue(len(l.literals) == 1)
def test_flatten(self): p = lambda x: boolean.parse(x, simplify=False) t1 = p("a * (b*c)") t2 = p("a*b*c") self.assertFalse(t1 == t2) self.assertTrue(t1.flatten() == t2) t1 = p("a + ((b*c) + (a*c)) + b") t2 = p("a + (b*c) + (a*c) + b") self.assertFalse(t1 == t2) self.assertTrue(t1.flatten() == t2)
def test_simplify(self): a = self.a b = self.b c = self.c _0 = boolean.FALSE _1 = boolean.TRUE # Idempotence self.assertTrue(a == a * a) # Idempotence + Associativity self.assertTrue(a + b == a + (a + b)) # Annihilation self.assertTrue(_0 == (a * _0)) self.assertTrue(_1 == (a + _1)) # Identity self.assertTrue(a == (a * _1)) self.assertTrue(a == (a + _0)) # Complementation self.assertTrue(_0 == a * ~a) self.assertTrue(_1 == a + ~a) # Absorption self.assertTrue(a == a * (a + b)) self.assertTrue(a == a + (a * b)) self.assertTrue(b * a == (b * a) + (b * a * c)) # Elimination self.assertTrue(a == (a * ~b) + (a * b)) expr = boolean.parse("(~a*b*c) + (a*~b*c) + (a*b*~c) + (a*b*c)") result = boolean.parse("(a*b)+(b*c)+(a*c)") self.assertTrue(expr == result) expr = boolean.parse("(~a*b*~c*~d) + (a*~b*~c*~d) + (a*~b*c*~d) +" "(a*~b*c*d) + (a*b*~c*~d) + (a*b*c*d)") result = boolean.parse("(~b*~d*a) + (~c*~d*b) + (a*c*d)") self.assertTrue(expr == result) expr = boolean.parse("(a*b*c*d) + (b*d)") result = boolean.parse("b*d") self.assertTrue(expr == result)
def test_printing(self): parse = lambda x: boolean.parse(x, eval=False) a = self.a b = self.b c = self.c self.assertTrue(str(parse("a*a")) == "a∙a") self.assertTrue(repr(parse("a*a")) == "AND(Symbol('a'), Symbol('a'))") self.assertTrue(str(parse("a+a")) == "a+a") self.assertTrue(repr(parse("a+a")) == "OR(Symbol('a'), Symbol('a'))") self.assertTrue(str(parse("(a+b)*c")) == "(a+b)∙c") self.assertTrue( repr(parse("(a+b)*c")) == "AND(OR(Symbol('a'), Symbol('b')), Symbol('c'))")
def test_parse_recognizes_trueish_and_falsish_symbol_tokens(self): expr_str = 'True or False or None or 0 or 1 or TRue or FalSE or NONe' expr = boolean.parse(expr_str, simplify=False) expected = boolean.OR( boolean.TRUE, boolean.FALSE, boolean.FALSE, boolean.FALSE, boolean.TRUE, boolean.TRUE, boolean.FALSE, boolean.FALSE, simplify=False ) self.assertEqual(expected, expr)
def test_flatten(self): p = lambda x: boolean.parse(x, eval=False) a = self.a b = self.b c = self.c t1 = p("a * (b*c)") t2 = p("a*b*c") self.assertFalse(t1 == t2) self.assertTrue(t1.flatten() == t2) t1 = p("a + ((b*c) + (a*c)) + b") t2 = p("a + (b*c) + (a*c) + b") self.assertFalse(t1 == t2) self.assertTrue(t1.flatten() == t2)
def simplify_expression(self, obj): try: txt = self.inp.text db = root.drawingboard sim_exp = boolean.parse(txt) exp = Label(text=str(sim_exp), pos=self.pos, size=self.size, font_size=75, color=[0, 0, 0, 1]) db.clear_widgets() db.add_widget(exp) self.error.text = "" except: error = "Invalid Expression" self.error.text = error
def test_parse_can_use_iterable_from_alternative_tokenizer(self): class CustomSymbol(boolean.Symbol): pass def tokenizer(s): "Sample tokenizer using custom operators and symbols" ops = { 'WHY_NOT': boolean.TOKEN_OR, 'ALSO': boolean.TOKEN_AND, 'NEITHER': boolean.TOKEN_NOT, '(': boolean.TOKEN_LPAR, ')': boolean.TOKEN_RPAR, } for row, line in enumerate(s.splitlines(False)): for col, tok in enumerate(line.split()): if tok in ops: yield ops[tok], tok, row, col elif tok == 'Custom': yield CustomSymbol(tok), tok, row, col else: yield boolean.Symbol(tok), tok, row, col expr_str = """( Custom WHY_NOT regular ) ALSO NEITHER ( not_custom ALSO standard ) """ tokenized = tokenizer(expr_str) expr = boolean.parse(tokenized, simplify=False) expected = boolean.AND( boolean.OR( CustomSymbol('Custom'), boolean.Symbol('regular'), simplify=False ), boolean.NOT( boolean.AND( boolean.Symbol('not_custom'), boolean.Symbol('standard'), simplify=False ), simplify=False ), simplify=False ) self.assertEqual(expected, expr)
def test_simplify_complex_expression_failing(self): a = boolean.Symbol('a') b = boolean.Symbol('b') c = boolean.Symbol('c') d = boolean.Symbol('d') test_expression = ''.join(("(~a*~b*~c*~d) + (~a*~b*~c*d) + (~a*b*~c*~d) +" "(~a*b*c*d) + (~a*b*~c*d) + (~a*b*c*~d) +" "(a*~b*~c*d) + (~a*b*c*d) + (a*~b*c*d) + (a*b*c*d)").split()) expected = eval(test_expression, None, dict(a=a, b=b, c=c, d=d)) parsed = boolean.parse(test_expression, simplify=True) # FIXME: THIS SHOULD NOT FAIL # we have a different simplify behavior for expressions built from python expressions # vs. expression built from an object tree vs. expression built from a parse self.assertEqual(str(parsed), str(expected))
def __init__(self, expression=None, input_dict={}, anonymous_symbols=True): Component.__init__(self) self._output = None if isinstance(expression, str): expression = boolean.parse(expression) if not isinstance(expression, boolean.Expression): raise ValueError( "Argument must be of type str or Expression but is type {}". format(expression.__class__)) if anonymous_symbols: new_input_dict = {} for symbol in (s for s in expression.symbols.copy()): # if s.obj != None): new_symbol = boolean.Symbol(None) expression = expression.subs({symbol: new_symbol}) if input_dict.get(symbol) is not None: new_input_dict[new_symbol] = input_dict[symbol] elif input_dict.get(str(symbol)) is not None: new_input_dict[new_symbol] = input_dict[str(symbol)] input_dict = new_input_dict else: def symbol_if_string(e): if isinstance(e, str): return boolean.Symbol(e) elif isinstance(e, boolean.Symbol): return e else: raise TypeError( "Argument must be of type str of Symbol but is type {}" .format(e.__class__)) input_dict = { symbol_if_string(k): v for k, v in input_dict.items() } self._expression = expression # inputs maps symbols to components # This can make an output to itself self.inputs = {s: None for s in expression.symbols} self.inputs.update(input_dict)
def test_parse_with_mixed_operators_multilines_and_custom_symbol(self): class MySymbol(boolean.Symbol): pass expr_str = """(a or ~ b +_c ) and #some comment d & ( ! e_ | (my * g OR 1 or 0) ) AND that """ expr = boolean.parse(expr_str, simplify=False, symbol_class=MySymbol) expected = boolean.AND( boolean.OR( MySymbol('a'), boolean.NOT(boolean.Symbol('b')), MySymbol('_c'), simplify=False ), MySymbol('d'), boolean.OR( boolean.NOT(MySymbol('e_')), boolean.OR( boolean.AND( MySymbol('my'), MySymbol('g'), simplify=False ), boolean.TRUE, boolean.FALSE, simplify=False ), simplify=False ), MySymbol('that'), simplify=False ) self.assertEqual(expected, expr)
def test_eval(self): a = self.a b = self.b c = self.c _0 = boolean.FALSE _1 = boolean.TRUE # Idempotence self.assertTrue(a == a * a) # Idempotence + Associativity self.assertTrue(a + b == a + (a + b)) # Annihilation self.assertTrue(_0 == (a * _0)) self.assertTrue(_1 == (a + _1)) # Identity self.assertTrue(a == (a * _1)) self.assertTrue(a == (a + _0)) # Complementation self.assertTrue(_0 == a * ~a) self.assertTrue(_1 == a + ~a) # Absorption self.assertTrue(a == a * (a + b)) self.assertTrue(a == a + (a * b)) self.assertTrue(b * a == (b * a) + (b * a * c)) # Elimination self.assertTrue(a == (a * ~b) + (a * b)) expr = boolean.parse("(~a*b*c) + (a*~b*c) + (a*b*~c) + (a*b*c)") result = boolean.parse("(a*b)+(b*c)+(a*c)") self.assertTrue(expr == result) expr = boolean.parse("(~a*b*~c*~d) + (a*~b*~c*~d) + (a*~b*c*~d) +" "(a*~b*c*d) + (a*b*~c*~d) + (a*b*c*d)") result = boolean.parse("(~b*~d*a) + (~c*~d*b) + (a*c*d)") self.assertTrue(expr == result) expr = boolean.parse("(a*b*c*d) + (b*d)") result = boolean.parse("b*d") self.assertTrue(expr == result) expr = boolean.parse( "(~a*~b*~c*~d) + (~a*~b*~c*d) + (~a*b*~c*~d) +" "(~a*b*c*d) + (~a*b*~c*d) + (~a*b*c*~d) +" "(a*~b*~c*d) + (~a*b*c*d) + (a*~b*c*d) + (a*b*c*d)")
def simplify(self, expr): sim_exp = boolean.parse(expr) exp = Simp(text=str(sim_exp), pos=self.pos, size=self.size) self.board.board_canvas.clear_widgets() self.board.board_canvas.add_widget(exp)
def on_deselect(self, others, keys, events): super().on_deselect(others, keys, events) try: self.text = str(boolean.parse(self.text, False)) except TypeError: pass
def test_dual(self): self.assertTrue(boolean.AND.getdual() is boolean.OR) self.assertTrue(boolean.OR.getdual() is boolean.AND) self.assertTrue(boolean.parse("a+b").dual is boolean.AND) self.assertTrue(boolean.parse("a*b").dual is boolean.OR)
def test_identity(self): self.assertTrue(boolean.parse("a+b").identity is boolean.FALSE) self.assertTrue(boolean.parse("a*b").identity is boolean.TRUE)
def test_annihilator(self): a = boolean.Symbol("a") p = lambda x: boolean.parse(x, eval=False) self.assertTrue(p("a*a").annihilator is boolean.FALSE) self.assertTrue(p("a+a").annihilator is boolean.TRUE)
def test_annihilator(self): p = lambda x: boolean.parse(x, simplify=False) self.assertTrue(p("a*a").annihilator is boolean.FALSE) self.assertTrue(p("a+a").annihilator is boolean.TRUE)
def test_demorgan(self): a, b, c = boolean.symbols("a", "b", "c") parse = lambda x: boolean.parse(x, eval=False) self.assertTrue(parse("~(a*b)").demorgan() == ~a + ~b) self.assertTrue(parse("~(a+b+c)").demorgan() == parse("~a*~b*~c")) self.assertTrue(parse("~(~a*b)").demorgan() == a + ~b)
def test_parse_with_advanced_tokenizer_example(self): class PlainVar(boolean.Symbol): "Plain boolean variable" class ColonDotVar(boolean.Symbol): "Colon and dot-separated string boolean variable" def advanced_tokenizer_example(expr): """ Example custom tokenizer derived from the standard tokenizer with this extra feature: a colon- and dot-separated string is recognized and stored in a custom symbol. Also, in contrast with the standard tokenizer, only these boolean operators are recognized : & | ! and or not. For more advanced tokenization you could also consider forking the `tokenize` standard library module. """ if not isinstance(expr, basestring): raise TypeError("expr must be string but it is %s." % type(expr)) # mapping of lowercase token strings to a token object instance for # standard operators, parens and common true or false symbols TOKENS = { '&': boolean.TOKEN_AND, 'and': boolean.TOKEN_AND, '|': boolean.TOKEN_OR, 'or': boolean.TOKEN_OR, '!': boolean.TOKEN_NOT, 'not': boolean.TOKEN_NOT, '(': boolean.TOKEN_LPAR, ')': boolean.TOKEN_RPAR, 'true': boolean.TRUE, '1': boolean.TRUE, 'false': boolean.FALSE, '0': boolean.FALSE, 'none': boolean.FALSE, } ignored_token_types = ( tokenize.NL, tokenize.NEWLINE, tokenize.COMMENT, tokenize.INDENT, tokenize.DEDENT, tokenize.ENDMARKER ) # note: an unbalanced expression may raise a TokenError here. tokens = ((toktype, tok, row, col,) for toktype, tok, (row, col,), _, _ in tokenize.generate_tokens(StringIO(expr).readline) if tok and tok.strip()) COLON_DOT = (':', '.',) def build_symbol(current_dotted): if current_dotted: if any(s in current_dotted for s in COLON_DOT): sym = ColonDotVar(current_dotted) else: sym = PlainVar(current_dotted) return sym # accumulator for dotted symbols that span several `tokenize` tokens dotted, srow, scol = '', None, None for toktype, tok, row, col in tokens: if toktype in ignored_token_types: # we reached a break point and should yield the current dotted symbol = build_symbol(dotted) if symbol is not None: yield symbol, dotted, srow, scol dotted, srow, scol = '', None, None continue std_token = TOKENS.get(tok.lower()) if std_token is not None: # we reached a break point and should yield the current dotted symbol = build_symbol(dotted) if symbol is not None: yield symbol, dotted, srow, scol dotted, srow, scol = '', 0, 0 yield std_token, tok, row, col continue if toktype == tokenize.NAME or (toktype == tokenize.OP and tok in COLON_DOT): if not dotted: srow = row scol = col dotted += tok else: raise TypeError('Unknown token: %(tok)r at line: %(row)r, column: %(col)r' % locals()) test_expr = """ (colon1:dot1.dot2 or colon2_name:col_on3:do_t1.do_t2.do_t3 ) and ( plain_symbol & !Custom ) """ tokenized = advanced_tokenizer_example(test_expr) expr = boolean.parse(tokenized, simplify=False) expected = boolean.AND( boolean.OR( ColonDotVar('colon1:dot1.dot2'), ColonDotVar('colon2_name:col_on3:do_t1.do_t2.do_t3'), simplify=False ), boolean.AND( PlainVar('plain_symbol'), boolean.NOT(PlainVar('Custom')), simplify=False ), simplify=False ) self.assertEqual(expected, expr)
def test_isliteral(self): s = boolean.Symbol(1) self.assertTrue(boolean.NOT(s).isliteral) self.assertFalse(boolean.parse("~(a+b)").isliteral)
def test_simplify_complex_expression(self): a = boolean.Symbol('a') b = boolean.Symbol('b') c = boolean.Symbol('c') d = boolean.Symbol('d') test_expression = ''.join(("(~a*~b*~c*~d) + (~a*~b*~c*d) + (~a*b*~c*~d) +" "(~a*b*c*d) + (~a*b*~c*d) + (~a*b*c*~d) +" "(a*~b*~c*d) + (~a*b*c*d) + (a*~b*c*d) + (a*b*c*d)").split()) expected = (a * ~b * d) + (~a * b) + (~a * ~c) + (b * c * d) self.assertEqual(expected, boolean.parse(test_expression, simplify=True)) expected = '(~a*~b*~c*~d)+(~a*~b*~c*d)+(~a*b*~c*~d)+(~a*b*c*d)+(~a*b*~c*d)+(~a*b*c*~d)+(a*~b*~c*d)+(~a*b*c*d)+(a*~b*c*d)+(a*b*c*d)' self.assertEqual(test_expression, str(boolean.parse(test_expression, simplify=False))) expected = '(a*~b*d)+(~a*b)+(~a*~c)+(b*c*d)' self.assertEqual(expected, str(boolean.parse(test_expression, simplify=True))) expected = boolean.OR( boolean.AND( boolean.NOT(boolean.Symbol('a')), boolean.NOT(boolean.Symbol('b')), boolean.NOT(boolean.Symbol('c')), boolean.NOT(boolean.Symbol('d')) ), boolean.AND( boolean.NOT(boolean.Symbol('a')), boolean.NOT(boolean.Symbol('b')), boolean.NOT(boolean.Symbol('c')), boolean.Symbol('d') ), boolean.AND( boolean.NOT(boolean.Symbol('a')), boolean.Symbol('b'), boolean.NOT(boolean.Symbol('c')), boolean.NOT(boolean.Symbol('d')) ), boolean.AND( boolean.NOT(boolean.Symbol('a')), boolean.Symbol('b'), boolean.Symbol('c'), boolean.Symbol('d')), boolean.AND( boolean.NOT(boolean.Symbol('a')), boolean.Symbol('b'), boolean.NOT(boolean.Symbol('c')), boolean.Symbol('d') ), boolean.AND( boolean.NOT(boolean.Symbol('a')), boolean.Symbol('b'), boolean.Symbol('c'), boolean.NOT(boolean.Symbol('d')) ), boolean.AND( boolean.Symbol('a'), boolean.NOT(boolean.Symbol('b')), boolean.NOT(boolean.Symbol('c')), boolean.Symbol('d') ), boolean.AND( boolean.NOT(boolean.Symbol('a')), boolean.Symbol('b'), boolean.Symbol('c'), boolean.Symbol('d') ), boolean.AND( boolean.Symbol('a'), boolean.NOT(boolean.Symbol('b')), boolean.Symbol('c'), boolean.Symbol('d') ), boolean.AND( boolean.Symbol('a'), boolean.Symbol('b'), boolean.Symbol('c'), boolean.Symbol('d') ) ) self.assertEqual(expected, boolean.parse(test_expression, simplify=True))
def renderable_components(expression, pos=(0, 0), bulb=True): """ Returns an list of renderable components when given an expression. """ if isinstance(expression, str): expression = boolean.parse(expression, eval=False) if not isinstance(expression, boolean.Expression): raise TypeError( "Argument must be str or Expression but it is {}" .format(expression.__class__)) r = [Bulb(pos)] symbol_dict = {} def recursive_components(e): # This function can be used if there is ever the want to attempt to make the # converted logic circuit look nicer by spacing the components def append(r_comp): r.append(r_comp) if isinstance(e, boolean.BaseElement): rc = Switch(pos) elif isinstance(e, boolean.Symbol): if e in symbol_dict.keys(): return symbol_dict[e] else: rc = Switch(pos) symbol_dict[e] = rc elif isinstance(e, boolean.NOT): pre = recursive_components(e.args[0]) w = Wire(pos, pos, pre.component) append(w) rc = Not(pos, w.component) elif isinstance(e, boolean.DualBase): if len(e.args) != 2: new_expr = e.__class__(e.args[0], e.args[1]) for i in range(2, len(e.args)): new_expr = e.__class__(new_expr, e.args[i], eval=False) e = new_expr pre0 = recursive_components(e.args[0]) pre1 = recursive_components(e.args[1]) w0 = Wire(pos, pos, pre0.component) w1 = Wire(pos, pos, pre1.component) append(w0) append(w1) if isinstance(e, boolean.AND): rc = And(pos) elif isinstance(e, boolean.OR): rc = Or(pos) c = rc.component c.inputs[c.empty_input_keys[0]] = w0.component c.inputs[c.empty_input_keys[0]] = w1.component append(rc) return rc recursive_components(expression) if bulb: w = Wire(pos, pos, r[-1].component) r[0].component.input = w.component r.append(w) else: r.pop(0) return r
def circuit_board(expression, bulb=True, eval=False): """ Takes an expression and converts it into a circuit board. """ if isinstance(expression, str): expression = boolean.parse(expression, eval=eval) if not isinstance(expression, boolean.Expression): raise TypeError( "Argument must be str or Expression but it is {}".format( expression.__class__)) # A list would work equally as well b = CircuitBoard() # A symbol can exist multiple times in an expression symbol_dict = {} def recursive_gate(e): """ Recursively adds components to the circuit board. """ if isinstance(e, boolean.BaseElement): # TODO: Either make the the same or create a constant component. s = Switch() b.append(s) return s elif isinstance(e, boolean.Symbol): if e in symbol_dict.keys(): return symbol_dict[e] else: s = Switch() symbol_dict[e] = s b.append(s) return s elif isinstance(e, boolean.Function): # All gates are of type Gate instead of And, Or and Not if e.order == (1, 1): pre = recursive_gate(e.args[0]) w = Wire(pre) b.append(w) s = boolean.Symbol(None) g = Gate(e.subs({e.args[0]: s}), {s: w}) b.append(g) return g else: input_dict = {} expr = e for arg in e.args: pre = recursive_gate(arg) w = Wire(pre) b.append(w) s = boolean.Symbol(None) expr = expr.subs({arg: s}) input_dict[s] = w g = Gate(expr, input_dict) b.append(g) return g recursive_gate(expression) if bulb: # Due to the nature of recursive_gate, the last component is last in the list w = Wire(b[-1]) o = Bulb(w) b.append(w) b.append(o) return b
def renderable_components(expression): """ Returns an list of renderable components when given an expression. """ if isinstance(expression, str): expression = boolean.parse(expression, eval=False) if not isinstance(expression, boolean.Expression): raise TypeError( "Argument must be str or Expression but it is {}" .format(expression.__class__)) def get_max_depth(e, max_depth, depth): if isinstance(e, boolean.Symbol): if max_depth < depth: max_depth += 1 return max_depth elif isinstance(e, boolean.NOT): if max_depth < depth: max_depth += 1 max_d = get_max_depth(e.args[0], max_depth, depth+1) elif isinstance(e, boolean.DualBase): if len(e.args) != 2: new_expr = e.__class__(e.args[0], e.args[1]) for i in range(2, len(e.args)): new_expr = e.__class__(new_expr, e.args[i], eval=False) e = new_expr if max_depth < depth: max_depth += 1 max_d0 = get_max_depth(e.args[0], max_depth, depth+1) max_d1 = get_max_depth(e.args[1], max_depth, depth+1) if max_d1 > max_d0: max_d = max_d1 else: max_d = max_d0 return max_d max_depth = get_max_depth(expression, 0, 0) width = (50 * (2 ** max_depth))/2 no_component = [0] symbols = {} no_symbols = [0] def recursive_components(e, depth, width): # This function can be used if there is ever the want to attempt to make the # converted logic circuit look nicer by spacing the components if isinstance(e, boolean.Symbol): if e in symbols.keys(): pos = symbols[e] rc = Symbol(str(e), pos=pos) else: x = 20 y = width pos = (x + (no_symbols[0] * 10), 35 + y) rc = Symbol(str(e), pos=pos) symbols[e] = pos no_symbols[0] += 1 elif isinstance(e, boolean.NOT): x = 35 + (120 * (max_depth - depth)) y = width pre = recursive_components(e.args[0], depth+1, width) pos = (x, 35 + y) no = str(no_component[0]) no_component[0] += 1 g = NotGate("N"+no, pos=pos) start = pre.get_output() stop = g.get_input() output = g.get_output() w = Wire(e.args[0], start, stop) temp = Temp(output=output) temp.add_widget(pre) temp.add_widget(w) temp.add_widget(g) rc = temp elif isinstance(e, boolean.DualBase): if len(e.args) != 2: new_expr = e.__class__(e.args[0], e.args[1]) for i in range(2, len(e.args)): new_expr = e.__class__(new_expr, e.args[i], eval=False) e = new_expr x = 35 + (120 * (max_depth - depth)) y = width w = ((50 * (2 ** (max_depth - depth)))/2) pre0 = recursive_components(e.args[0], depth + 1, width + w/2) pre1 = recursive_components(e.args[1], depth + 1, width - w/2) pos = (x, 35 + y) no = str(no_component[0]) no_component[0] += 1 if isinstance(e, boolean.AND): g = AndGate("A"+no, pos=pos) elif isinstance(e, boolean.OR): g = OrGate("O"+no, pos=pos) start0 = pre0.get_output() stop0 = g.get_input1() start1 = pre1.get_output() stop1 = g.get_input2() output = g.get_output() w0 = Wire(e.args[0], start0, stop0) w1 = Wire(e.args[1], start1, stop1) temp = Temp(output=output) temp.add_widget(pre0) temp.add_widget(pre1) temp.add_widget(w0) temp.add_widget(w1) temp.add_widget(g) rc = temp return rc rc = recursive_components(expression, 0, width) pos = (35 + (120 * (max_depth + 1)), width + 35) g = Output(str(expression), pos=pos) start = rc.get_output() stop = g.get_input() w0 = Wire("", start, stop) temp = Temp(height=2*width, width=max_depth*120+35) temp.add_widget(g) temp.add_widget(rc) temp.add_widget(w0) # temp.size = (max_depth * 125, width) return temp