Skip to content

Commit

Permalink
truth table creation
Browse files Browse the repository at this point in the history
  • Loading branch information
dakk committed Sep 29, 2023
1 parent 47f9027 commit ba39423
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 25 deletions.
4 changes: 4 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- [x] Ast2logic: fix type inference on assign
- [x] Ast2logic: handle multiple result
- [x] Ast2logic: fix ret_type for multiple results
- [x] QlassF: truth table creation
- [ ] Extend testing to compilation
- [ ] Int arithmetic expressions
- [ ] Compiler: prepare invertible abstraction
Expand All @@ -31,12 +32,15 @@
- [ ] Compiler: base invertible to qcircuit translator

### Week 4: (16 Oct 23)
- [ ] Ast2logic: fixed size loops unrolling
- [ ] Invertible representation simplification (to reduce number of garbage wires)
- [ ] Garbage uncomputing and recycling

## Month 2:

### Week 1: (23 Oct 23)
- [ ] Parametrized qlassf

### Week 2: (30 Oct 23)
### Week 3: (6 Nov 23)

Expand Down
2 changes: 1 addition & 1 deletion qlasskit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@

from . import exceptions # noqa: F401
from .qlassf import QlassF, qlassf # noqa: F401
from .typing import Qtype # noqa: F401
from .typing import Qint2, Qint4, Qint8, Qint12, Qint16, Qtype # noqa: F401
5 changes: 3 additions & 2 deletions qlasskit/ast2logic/t_expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@

from sympy import Symbol
from sympy.logic import ITE, And, Not, Or, false, true
from sympy.logic.boolalg import Boolean

from .. import exceptions
from ..typing import BoolExp, Env
from ..typing import Env


def type_of_exp(vlist, base, env, res=[]):
Expand All @@ -39,7 +40,7 @@ def type_of_exp(vlist, base, env, res=[]):
return [new_symb], env


def translate_expression(expr, env: Env) -> BoolExp: # noqa: C901
def translate_expression(expr, env: Env) -> Boolean: # noqa: C901
"""Translate an expression"""

# Name reference
Expand Down
7 changes: 4 additions & 3 deletions qlasskit/ast2logic/t_statement.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@
from typing import List, Tuple

from sympy import Symbol
from sympy.logic.boolalg import Boolean

from .. import exceptions
from ..typing import BoolExp, Env
from ..typing import Env
from . import translate_expression, type_of_exp


def translate_statement( # noqa: C901
stmt, env: Env
) -> Tuple[List[Tuple[str, BoolExp]], Env]:
) -> Tuple[List[Tuple[str, Boolean]], Env]:
"""Parse a statement"""
# match stmt:
if isinstance(stmt, ast.If):
Expand Down Expand Up @@ -56,7 +57,7 @@ def translate_statement( # noqa: C901
target = stmt.targets[0].id

if target in env:
raise exceptions.SymbolReassingedException(target)
raise exceptions.SymbolReassignedException(target)

val = translate_expression(stmt.value, env)
res, env = type_of_exp(val, f"{target}", env)
Expand Down
5 changes: 3 additions & 2 deletions qlasskit/compiler/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@

from sympy import Symbol, simplify, symbols
from sympy.logic import ITE, And, Implies, Not, Or, boolalg
from sympy.logic.boolalg import Boolean

from ..typing import BoolExp, BoolExpList
from ..typing import BoolExpList


class CompilerException(Exception):
Expand Down Expand Up @@ -88,7 +89,7 @@ def compile(self, exprs: BoolExpList):
if sym == Symbol("_ret"): # TODO: this won't work with multiple res
return iret, gl

def compile_expr(self, expr: BoolExp): # noqa: C901
def compile_expr(self, expr: Boolean): # noqa: C901
# match expr:
if isinstance(expr, Symbol):
if expr.name not in self.qmap:
Expand Down
2 changes: 1 addition & 1 deletion qlasskit/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@ def __init__(self, name, val):
super().__init__(f"{name} is costant = {val}")


class SymbolReassingedException(Exception):
class SymbolReassignedException(Exception):
def __init__(self, name):
super().__init__(f"{name} cannot be reassinged")
34 changes: 34 additions & 0 deletions qlasskit/qlassf.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
from .typing import * # noqa: F403, F401
from .typing import Args, BoolExpList

MAX_TRUTH_TABLE_SIZE = 20


class QlassF:
"""Class representing a quantum classical circuit"""
Expand Down Expand Up @@ -55,6 +57,38 @@ def __add__(self, qf2) -> "QlassF":
"""Adds two qlassf and return the combination"""
raise Exception("not implemented")

def truth_table_header(self) -> List[str]:
"""Returns the list of string containing the truth table header"""
header = [x for x in self.args]
header.extend([sym.name for (sym, retex) in self.expressions[-self.ret_size :]])
return header

def truth_table(self) -> List[List[bool]]:
"""Returns the truth table for the function using the sympy boolean for computing"""
truth = []
bits = len(self.args)

if (bits + self.ret_size) > MAX_TRUTH_TABLE_SIZE:
raise Exception(
f"Max truth table size reached: {bits + self.ret_size} > {MAX_TRUTH_TABLE_SIZE}"
)

for i in range(2**bits):
bin_str = bin(i)[2:]
bin_str = "0" * (bits - len(bin_str)) + bin_str
bin_arr = list(map(lambda c: c == "1", bin_str))
known = list(zip(self.args, bin_arr))

for ename, exp in self.expressions:
exp_sub = exp.subs(known)
known.append((ename, exp_sub))

res = known[0 : len(self.args)] + known[-self.ret_size :]
res_clean = list(map(lambda y: y[1], res))
truth.append(res_clean)

return truth

def compile(self):
# TODO: compile all expression and create a one gate only
self._compiled_gate = compiler.to_quantum(self.expressions)
Expand Down
7 changes: 3 additions & 4 deletions qlasskit/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import List, Tuple, Union
from typing import List, Tuple

from sympy import Symbol
from sympy.logic import ITE, And, Not, Or
from sympy.logic.boolalg import Boolean

Args = List[str]
Env = List[str]
BoolExp = Union[Symbol, And, Or, Not, ITE, bool]
BoolExpList = List[Tuple[Symbol, BoolExp]]
BoolExpList = List[Tuple[Symbol, Boolean]]
LogicFun = Tuple[str, Args, int, BoolExpList]


Expand Down
86 changes: 86 additions & 0 deletions test/test_qlassf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import unittest

from qlasskit import Qint4, QlassF, qlassf

from . import utils


class TestQlassfDecorator(unittest.TestCase):
def test_decorator(self):
c = qlassf(utils.test_not, to_compile=False)
self.assertTrue(isinstance(c, QlassF))


class TestQlassfTruthTable(unittest.TestCase):
def test_not_truth(self):
f = "def test(a: bool) -> bool:\n\treturn not a"
qf = qlassf(f, to_compile=False)
tt = qf.truth_table()
self.assertEqual(
tt,
[[False, True], [True, False]],
)

def test_and_truth(self):
f = "def test(a: bool, b: bool) -> bool:\n\treturn a and b"
qf = qlassf(f, to_compile=False)
tt = qf.truth_table()
self.assertEqual(
tt,
[
[False, False, False],
[False, True, False],
[True, False, False],
[True, True, True],
],
)

def test_or_truth(self):
f = "def test(a: bool, b: bool) -> bool:\n\treturn a or b"
qf = qlassf(f, to_compile=False)
tt = qf.truth_table()
self.assertEqual(
tt,
[
[False, False, False],
[False, True, True],
[True, False, True],
[True, True, True],
],
)

def test_big_truth(self):
f = "def test(a: Qint4) -> Qint4:\n\treturn a"
qf = qlassf(f, to_compile=False)
tt = qf.truth_table()
tth = qf.truth_table_header()

self.assertEqual(
tth, ["a.0", "a.1", "a.2", "a.3", "_ret.0", "_ret.1", "_ret.2", "_ret.3"]
)
self.assertEqual(
tt,
[
[False, False, False, False] * 2,
[False, False, False, True] * 2,
[False, False, True, False] * 2,
[False, False, True, True] * 2,
[False, True, False, False] * 2,
[False, True, False, True] * 2,
[False, True, True, False] * 2,
[False, True, True, True] * 2,
[True, False, False, False] * 2,
[True, False, False, True] * 2,
[True, False, True, False] * 2,
[True, False, True, True] * 2,
[True, True, False, False] * 2,
[True, True, False, True] * 2,
[True, True, True, False] * 2,
[True, True, True, True] * 2,
],
)

def test_too_big_truth(self):
f = "def test(a: Qint12) -> Qint12:\n\treturn a"
qf = qlassf(f, to_compile=False)
self.assertRaises(Exception, lambda: qf.truth_table())
2 changes: 1 addition & 1 deletion test/test_qlassf_bool.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def test_assign3(self):
def test_reassign_exception(self):
f = "def test(a: bool) -> bool:\n\ta = not a\n\treturn a"
self.assertRaises(
exceptions.SymbolReassingedException,
exceptions.SymbolReassignedException,
lambda f: qlassf(f, to_compile=False),
f,
)
Expand Down
11 changes: 0 additions & 11 deletions test/test_qlassf_decorator.py

This file was deleted.

0 comments on commit ba39423

Please sign in to comment.