Coverage for /home/runner/work/tket/tket/pytket/pytket/circuit/logic_exp.py: 88%
555 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-14 11:30 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-14 11:30 +0000
1# Copyright Quantinuum
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
15"""Classes and functions for constructing logical
16expressions over Bit and BitRegister."""
17from collections.abc import Iterable, Iterator, Sequence
18from dataclasses import dataclass
19from enum import Enum
20from typing import Any, ClassVar, TypeVar, Union, cast
22from pytket.circuit import Bit, BitRegister
24T = TypeVar("T")
27def filter_by_type(seq: Iterable, var_type: type[T]) -> Iterator[tuple[int, T]]:
28 """Return enumeration of seq, with only elements of type var_type."""
29 return filter(lambda x: isinstance(x[1], var_type), enumerate(seq))
32class BitWiseOp(Enum):
33 """Enum for operations on Bit."""
35 AND = "&"
36 OR = "|"
37 XOR = "^"
38 EQ = "=="
39 NEQ = "!="
40 NOT = "~"
41 ZERO = "0"
42 ONE = "1"
45class RegWiseOp(Enum):
46 """Enum for operations on BitRegister."""
48 AND = "&"
49 OR = "|"
50 XOR = "^"
51 EQ = "=="
52 NEQ = "!="
53 LT = "<"
54 GT = ">"
55 LEQ = "<="
56 GEQ = ">="
57 ADD = "+"
58 SUB = "-"
59 MUL = "*"
60 DIV = "/"
61 POW = "**"
62 LSH = "<<"
63 RSH = ">>"
64 NOT = "~"
65 NEG = "-" # noqa: PIE796
68Ops = Union[BitWiseOp, RegWiseOp] # all op enum types
71Constant = int # constants in expression
72Variable = Union[Bit, BitRegister] # variables in expression
73ArgType = Union["LogicExp", Variable, Constant] # all possible arguments in expression
76@dataclass(init=False)
77class LogicExp:
78 """Logical expressions over Bit or BitRegister.
79 Encoded as a tree of expressions"""
81 op: Ops # enum for operation encoded by this node
82 args: list[ArgType] # arguments of operation
83 # class level dictionary mapping enum to class
84 op_cls_dict: ClassVar[dict[Ops, type["LogicExp"]]] = dict()
86 @classmethod
87 def factory(cls, op: Ops) -> type["LogicExp"]:
88 """Return matching operation class for enum."""
89 # RegNeg cannot be initialised this way as "-" clashes with SUB
90 if op == BitWiseOp.AND:
91 return BitAnd
92 if op == BitWiseOp.OR:
93 return BitOr
94 if op == BitWiseOp.XOR:
95 return BitXor
96 if op == BitWiseOp.NOT:
97 return BitNot
98 if op == BitWiseOp.EQ:
99 return BitEq
100 if op == BitWiseOp.NEQ:
101 return BitNeq
102 if op == BitWiseOp.ZERO:
103 return BitZero
104 if op == BitWiseOp.ONE:
105 return BitOne
106 if op == RegWiseOp.AND:
107 return RegAnd
108 if op == RegWiseOp.OR:
109 return RegOr
110 if op == RegWiseOp.XOR: 110 ↛ 111line 110 didn't jump to line 111 because the condition on line 110 was never true
111 return RegXor
112 if op == RegWiseOp.ADD:
113 return RegAdd
114 if op == RegWiseOp.SUB:
115 return RegSub
116 if op == RegWiseOp.MUL:
117 return RegMul
118 if op == RegWiseOp.DIV:
119 return RegDiv
120 if op == RegWiseOp.POW: 120 ↛ 121line 120 didn't jump to line 121 because the condition on line 120 was never true
121 return RegPow
122 if op == RegWiseOp.LSH:
123 return RegLsh
124 if op == RegWiseOp.RSH: 124 ↛ 125line 124 didn't jump to line 125 because the condition on line 124 was never true
125 return RegRsh
126 if op == RegWiseOp.EQ: 126 ↛ 127line 126 didn't jump to line 127 because the condition on line 126 was never true
127 return RegEq
128 if op == RegWiseOp.NEQ:
129 return RegNeq
130 if op == RegWiseOp.LT: 130 ↛ 131line 130 didn't jump to line 131 because the condition on line 130 was never true
131 return RegLt
132 if op == RegWiseOp.GT:
133 return RegGt
134 if op == RegWiseOp.LEQ:
135 return RegLeq
136 if op == RegWiseOp.GEQ: 136 ↛ 137line 136 didn't jump to line 137 because the condition on line 136 was never true
137 return RegGeq
138 if op == RegWiseOp.NOT: 138 ↛ 140line 138 didn't jump to line 140 because the condition on line 138 was always true
139 return RegNot
140 raise ValueError("op type not supported")
142 def set_value(self, var: Variable, val: Constant) -> None:
143 """Set value of var to val recursively."""
144 for i, arg in enumerate(self.args):
145 if isinstance(arg, (Bit, BitRegister)):
146 if arg == var:
147 self.args[i] = val
148 elif isinstance(arg, LogicExp): 148 ↛ 149line 148 didn't jump to line 149 because the condition on line 148 was never true
149 arg.set_value(var, val)
151 @staticmethod
152 def _const_eval(args: list[Constant]) -> Constant:
153 """Evaluate expression given constant values for all args."""
154 raise NotImplementedError
156 def eval_vals(self) -> ArgType:
157 """Attempt to evaluate all sub-expressions; simple constant folding."""
158 rval: ArgType = self
159 for i, arg in filter_by_type(self.args, LogicExp): 159 ↛ 160line 159 didn't jump to line 160 because the loop on line 159 never started
160 self.args[i] = arg.eval_vals()
161 if all(isinstance(a, Constant) for a in self.args): 161 ↛ 166line 161 didn't jump to line 166 because the condition on line 161 was always true
162 try:
163 rval = self._const_eval(cast(list[Constant], self.args))
164 except NotImplementedError:
165 pass
166 return rval
168 def all_inputs(self) -> set[Variable]:
169 """
170 :return: All variables involved in expression.
171 :rtype: Set[Variable]
172 """
173 outset: set[Variable] = set()
175 for arg in self.args:
176 if isinstance(arg, LogicExp):
177 outset.update(arg.all_inputs())
178 continue
179 if isinstance(self, BitLogicExp):
180 if isinstance(arg, Bit):
181 outset.add(arg)
182 elif isinstance(arg, BitRegister):
183 outset.add(arg)
184 return outset
186 def all_inputs_ordered(self) -> list[Variable]:
187 """
188 :return: All variables involved in expression, in order of first appearance.
189 :rtype: list[Variable]
190 """
191 # use dict[Variable, None] instead of set[Variable] to preserve order
192 outset: dict[Variable, None] = {}
194 for arg in self.args:
195 if isinstance(arg, LogicExp):
196 outset.update(dict.fromkeys(arg.all_inputs_ordered()))
197 continue
198 if isinstance(self, BitLogicExp):
199 if isinstance(arg, Bit):
200 outset[arg] = None
201 elif isinstance(arg, BitRegister):
202 outset[arg] = None
203 return list(outset)
205 def __eq__(self, other: object) -> bool:
206 if not isinstance(other, LogicExp): 206 ↛ 207line 206 didn't jump to line 207 because the condition on line 206 was never true
207 return False
208 return (self.op == other.op) and (self.args == other.args)
210 def to_dict(self) -> dict[str, Any]:
211 """Output JSON serializable nested dictionary."""
212 out: dict[str, Any] = {"op": str(self.op)}
213 args_ser: list[dict | Constant | list[str | int]] = []
215 for arg in self.args:
216 if isinstance(arg, LogicExp):
217 args_ser.append(arg.to_dict())
218 elif isinstance(arg, Constant):
219 args_ser.append(arg)
220 elif isinstance(arg, Bit):
221 args_ser.append(arg.to_list())
222 elif isinstance(arg, BitRegister): 222 ↛ 215line 222 didn't jump to line 215 because the condition on line 222 was always true
223 args_ser.append({"name": arg.name, "size": arg.size})
225 out["args"] = args_ser
226 return out
228 @classmethod
229 def from_dict(cls, dic: dict[str, Any]) -> "LogicExp":
230 """Load from JSON serializable nested dictionary."""
231 opset_name, op_name = dic["op"].split(".", 2)
232 opset = BitWiseOp if opset_name == "BitWiseOp" else RegWiseOp
233 op = next(o for o in opset if o.name == op_name)
234 args: list[ArgType] = []
235 for arg_ser in dic["args"]:
236 if isinstance(arg_ser, Constant):
237 args.append(arg_ser)
238 elif isinstance(arg_ser, list):
239 args.append(Bit(arg_ser[0], arg_ser[1]))
240 elif isinstance(arg_ser, dict): 240 ↛ 235line 240 didn't jump to line 235 because the condition on line 240 was always true
241 if "op" in arg_ser:
242 args.append(LogicExp.from_dict(arg_ser))
243 else:
244 args.append(BitRegister(arg_ser["name"], arg_ser["size"]))
245 return create_logic_exp(op, args)
247 def _rename_args_recursive(
248 self, cmap: dict[Bit, Bit], renamed_regs: set[str]
249 ) -> bool:
250 success = False
251 for i, arg in enumerate(self.args):
252 if isinstance(arg, Bit):
253 if arg in cmap:
254 self.args[i] = cmap[arg]
255 success = True
256 elif isinstance(arg, BitRegister):
257 if arg.name in renamed_regs:
258 raise ValueError(
259 f"""Can't rename bits in {arg.__repr__()} """
260 """because the register is being used """
261 """in a register-wise logic expression."""
262 )
263 elif isinstance(arg, LogicExp):
264 success |= arg._rename_args_recursive(cmap, renamed_regs)
265 return success
267 def rename_args(self, cmap: dict[Bit, Bit]) -> bool:
268 """Rename the Bits according to a Bit map. Raise ValueError if
269 a bit is being used in a register-wise expression.
270 """
271 if all(old_bit == new_bit for old_bit, new_bit in cmap.items()):
272 return False
273 renamed_regs = set([key.reg_name for key in cmap])
274 return self._rename_args_recursive(cmap, renamed_regs)
277BitArgType = Union[LogicExp, Bit, Constant]
278RegArgType = Union[LogicExp, BitRegister, Constant]
281class BitLogicExp(LogicExp):
282 """Expression acting only on Bit or Constant types."""
284 def __and__(self, other: BitArgType) -> "BitAnd":
285 return BitAnd(self, other)
287 def __rand__(self, other: BitArgType) -> "BitAnd":
288 return BitAnd(self, other)
290 def __or__(self, other: BitArgType) -> "BitOr":
291 return BitOr(self, other)
293 def __ror__(self, other: BitArgType) -> "BitOr":
294 return BitOr(self, other)
296 def __xor__(self, other: BitArgType) -> "BitXor":
297 return BitXor(self, other)
299 def __rxor__(self, other: BitArgType) -> "BitXor":
300 return BitXor(self, other)
303class RegLogicExp(LogicExp):
304 """Expression acting only on BitRegister or Constant types."""
306 def __and__(self, other: RegArgType) -> "RegAnd":
307 return RegAnd(self, other)
309 def __rand__(self, other: RegArgType) -> "RegAnd":
310 return RegAnd(self, other)
312 def __or__(self, other: RegArgType) -> "RegOr":
313 return RegOr(self, other)
315 def __ror__(self, other: RegArgType) -> "RegOr":
316 return RegOr(self, other)
318 def __xor__(self, other: RegArgType) -> "RegXor":
319 return RegXor(self, other)
321 def __rxor__(self, other: RegArgType) -> "RegXor":
322 return RegXor(self, other)
324 def __add__(self, other: RegArgType) -> "RegAdd":
325 return RegAdd(self, other)
327 def __sub__(self, other: RegArgType) -> "RegSub":
328 return RegSub(self, other)
330 def __mul__(self, other: RegArgType) -> "RegMul":
331 return RegMul(self, other)
333 def __floordiv__(self, other: RegArgType) -> "RegDiv":
334 return RegDiv(self, other)
336 def __pow__(self, other: RegArgType) -> "RegPow":
337 return RegPow(self, other)
339 def __lshift__(self, other: RegArgType) -> "RegLsh":
340 return RegLsh(self, other)
342 def __rshift__(self, other: RegArgType) -> "RegRsh":
343 return RegRsh(self, other)
346class BinaryOp(LogicExp):
347 """Expresion for operation on two arguments."""
349 def __str__(self) -> str:
350 return f"({self.args[0]} {self.op.value} {self.args[1]})"
353class UnaryOp(LogicExp):
354 """Expression for operation on one argument."""
356 def __str__(self) -> str:
357 return f"({self.op.value} {self.args[0]})"
360class NullaryOp(LogicExp):
361 """Expression for operation on no arguments (i.e. constant)."""
363 def __str__(self) -> str:
364 return f"({self.op.value})"
367class And(BinaryOp):
368 @staticmethod
369 def _const_eval(args: list[Constant]) -> Constant:
370 return args[0] & args[1]
372 def eval_vals(self) -> ArgType:
373 rval: ArgType = super().eval_vals()
374 if 0 in self.args:
375 return 0
376 return rval
379class Or(BinaryOp):
380 @staticmethod
381 def _const_eval(args: list[Constant]) -> Constant:
382 return args[0] | args[1]
385class Xor(BinaryOp):
386 @staticmethod
387 def _const_eval(args: list[Constant]) -> Constant:
388 return args[0] ^ args[1]
391class BitAnd(And, BitLogicExp):
392 def __init__(self, arg1: BitArgType, arg2: BitArgType) -> None:
393 self.op = BitWiseOp.AND
394 self.args = [arg1, arg2]
397class BitOr(Or, BitLogicExp):
398 def __init__(self, arg1: BitArgType, arg2: BitArgType) -> None:
399 self.op = BitWiseOp.OR
400 self.args = [arg1, arg2]
402 def eval_vals(self) -> ArgType:
403 rval: ArgType = super().eval_vals()
404 if 1 in self.args:
405 return 1
406 return rval
409class BitXor(Xor, BitLogicExp):
410 def __init__(self, arg1: BitArgType, arg2: BitArgType) -> None:
411 self.op = BitWiseOp.XOR
412 self.args = [arg1, arg2]
415class BitNot(UnaryOp, BitLogicExp):
416 def __init__(self, arg1: BitArgType) -> None:
417 self.op = BitWiseOp.NOT
418 self.args = [arg1]
420 @staticmethod
421 def _const_eval(args: list[Constant]) -> Constant:
422 return 1 - args[0]
425class BitZero(NullaryOp, BitLogicExp):
426 def __init__(self) -> None:
427 self.op = BitWiseOp.ZERO
428 self.args = []
430 @staticmethod
431 def _const_eval(args: list[Constant]) -> Constant:
432 return 0
435class BitOne(NullaryOp, BitLogicExp):
436 def __init__(self) -> None:
437 self.op = BitWiseOp.ONE
438 self.args = []
440 @staticmethod
441 def _const_eval(args: list[Constant]) -> Constant:
442 return 1
445class RegAnd(And, RegLogicExp):
446 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
447 self.op = RegWiseOp.AND
448 self.args = [arg1, arg2]
451class RegOr(Or, RegLogicExp):
452 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
453 self.op = RegWiseOp.OR
454 self.args = [arg1, arg2]
457class RegXor(Xor, RegLogicExp):
458 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
459 self.op = RegWiseOp.XOR
460 self.args = [arg1, arg2]
463class RegAdd(BinaryOp, RegLogicExp):
464 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
465 self.op = RegWiseOp.ADD
466 self.args = [arg1, arg2]
469class RegSub(BinaryOp, RegLogicExp):
470 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
471 self.op = RegWiseOp.SUB
472 self.args = [arg1, arg2]
475class RegMul(BinaryOp, RegLogicExp):
476 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
477 self.op = RegWiseOp.MUL
478 self.args = [arg1, arg2]
481class RegDiv(BinaryOp, RegLogicExp):
482 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
483 self.op = RegWiseOp.DIV
484 self.args = [arg1, arg2]
487class RegPow(BinaryOp, RegLogicExp):
488 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
489 self.op = RegWiseOp.POW
490 self.args = [arg1, arg2]
493class RegLsh(BinaryOp, RegLogicExp):
494 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
495 self.op = RegWiseOp.LSH
496 self.args = [arg1, arg2]
499class RegNeg(UnaryOp, RegLogicExp):
500 def __init__(self, arg1: RegArgType) -> None:
501 self.op = RegWiseOp.NEG
502 self.args = [arg1]
505class RegNot(UnaryOp, RegLogicExp):
506 def __init__(self, arg1: RegArgType) -> None:
507 self.op = RegWiseOp.NOT
508 self.args = [arg1]
511class RegRsh(BinaryOp, RegLogicExp):
512 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
513 self.op = RegWiseOp.RSH
514 self.args = [arg1, arg2]
517class PredicateExp(BinaryOp):
518 """
519 A binary predicate where the arguments are either
520 Bits, BitRegisters, or Constants.
521 """
524class Eq(PredicateExp):
525 @staticmethod
526 def _const_eval(args: list[Constant]) -> Constant:
527 return args[0] == args[1]
530class Neq(PredicateExp):
531 @staticmethod
532 def _const_eval(args: list[Constant]) -> Constant:
533 return 1 - Eq._const_eval(args)
536class BitEq(Eq, BitLogicExp):
537 def __init__(self, arg1: BitArgType, arg2: BitArgType) -> None:
538 self.op = BitWiseOp.EQ
539 self.args = [arg1, arg2]
542class BitNeq(Neq, BitLogicExp):
543 def __init__(self, arg1: BitArgType, arg2: BitArgType) -> None:
544 self.op = BitWiseOp.NEQ
545 self.args = [arg1, arg2]
548class RegEq(Eq, RegLogicExp):
549 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
550 self.op = RegWiseOp.EQ
551 self.args = [arg1, arg2]
554class RegNeq(Neq, RegLogicExp):
555 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
556 self.op = RegWiseOp.NEQ
557 self.args = [arg1, arg2]
560class RegLt(PredicateExp, RegLogicExp):
561 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
562 self.op = RegWiseOp.LT
563 self.args = [arg1, arg2]
565 @staticmethod
566 def _const_eval(args: list[Constant]) -> Constant:
567 return args[0] < args[1]
570class RegGt(PredicateExp, RegLogicExp):
571 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
572 self.op = RegWiseOp.GT
573 self.args = [arg1, arg2]
575 @staticmethod
576 def _const_eval(args: list[Constant]) -> Constant:
577 return args[0] > args[1]
580class RegLeq(PredicateExp, RegLogicExp):
581 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
582 self.op = RegWiseOp.LEQ
583 self.args = [arg1, arg2]
585 @staticmethod
586 def _const_eval(args: list[Constant]) -> Constant:
587 return args[0] <= args[1]
590class RegGeq(PredicateExp, RegLogicExp):
591 def __init__(self, arg1: RegArgType, arg2: RegArgType) -> None:
592 self.op = RegWiseOp.GEQ
593 self.args = [arg1, arg2]
595 @staticmethod
596 def _const_eval(args: list[Constant]) -> Constant:
597 return args[0] >= args[1]
600def reg_eq(register: RegLogicExp | BitRegister, value: Constant) -> RegLogicExp:
601 """Function to express a BitRegister equality predicate, i.e.
602 for a register ``r``, ``(r == 5)`` is expressed as ``reg_eq(r, 5)``"""
603 return RegEq(register, value)
606def reg_neq(register: RegLogicExp | BitRegister, value: Constant) -> RegLogicExp:
607 """Function to express a BitRegister inequality predicate, i.e.
608 for a register ``r``, ``(r != 5)`` is expressed as ``reg_neq(r, 5)``"""
609 return RegNeq(register, value)
612def reg_lt(register: RegLogicExp | BitRegister, value: Constant) -> RegLogicExp:
613 """Function to express a BitRegister less than predicate, i.e.
614 for a register ``r``, ``(r < 5)`` is expressed as ``reg_lt(r, 5)``"""
615 return RegLt(register, value)
618def reg_gt(register: RegLogicExp | BitRegister, value: Constant) -> RegLogicExp:
619 """Function to express a BitRegister greater than predicate, i.e.
620 for a register ``r``, ``(r > 5)`` is expressed as ``reg_gt(r, 5)``"""
621 return RegGt(register, value)
624def reg_leq(register: RegLogicExp | BitRegister, value: Constant) -> RegLogicExp:
625 """Function to express a BitRegister less than or equal to predicate,
626 i.e. for a register ``r``, ``(r <= 5)`` is expressed as ``reg_leq(r, 5)``"""
627 return RegLeq(register, value)
630def reg_geq(register: RegLogicExp | BitRegister, value: Constant) -> RegLogicExp:
631 """Function to express a BitRegister greater than or equal to
632 predicate, i.e. for a register ``r``, ``(r >= 5)`` is expressed as
633 ``reg_geq(r, 5)``"""
634 return RegGeq(register, value)
637def if_bit(bit: Bit | BitLogicExp) -> PredicateExp:
638 """Equivalent of ``if bit:``."""
639 return BitEq(bit, 1)
642def if_not_bit(bit: Bit | BitLogicExp) -> PredicateExp:
643 """Equivalent of ``if not bit:``."""
644 return BitEq(bit, 0)
647def create_bit_logic_exp(op: BitWiseOp, args: Sequence[BitArgType]) -> BitLogicExp:
648 if op == BitWiseOp.AND:
649 assert len(args) == 2
650 return BitAnd(args[0], args[1])
651 if op == BitWiseOp.OR:
652 assert len(args) == 2
653 return BitOr(args[0], args[1])
654 if op == BitWiseOp.XOR:
655 assert len(args) == 2
656 return BitXor(args[0], args[1])
657 if op == BitWiseOp.NOT:
658 assert len(args) == 1
659 return BitNot(args[0])
660 if op == BitWiseOp.EQ:
661 assert len(args) == 2
662 return BitEq(args[0], args[1])
663 if op == BitWiseOp.NEQ:
664 assert len(args) == 2
665 return BitNeq(args[0], args[1])
666 if op == BitWiseOp.ZERO:
667 assert len(args) == 0
668 return BitZero()
669 if op == BitWiseOp.ONE: # noqa: RET503 669 ↛ exitline 669 didn't return from function 'create_bit_logic_exp' because the condition on line 669 was always true
670 assert len(args) == 0
671 return BitOne()
674def create_reg_logic_exp(op: RegWiseOp, args: Sequence[RegArgType]) -> RegLogicExp:
675 if op == RegWiseOp.AND:
676 assert len(args) == 2
677 return RegAnd(args[0], args[1])
678 if op == RegWiseOp.OR:
679 assert len(args) == 2
680 return RegOr(args[0], args[1])
681 if op == RegWiseOp.XOR:
682 assert len(args) == 2
683 return RegXor(args[0], args[1])
684 if op == RegWiseOp.ADD:
685 assert len(args) == 2
686 return RegAdd(args[0], args[1])
687 if op == RegWiseOp.SUB:
688 if len(args) == 2: 688 ↛ 690line 688 didn't jump to line 690 because the condition on line 688 was always true
689 return RegSub(args[0], args[1])
690 if len(args) == 1:
691 return RegNeg(args[0])
692 if op == RegWiseOp.NEG: 692 ↛ 693line 692 didn't jump to line 693 because the condition on line 692 was never true
693 assert len(args) == 1
694 return RegNeg(args[0])
695 if op == RegWiseOp.MUL:
696 assert len(args) == 2
697 return RegMul(args[0], args[1])
698 if op == RegWiseOp.DIV:
699 assert len(args) == 2
700 return RegDiv(args[0], args[1])
701 if op == RegWiseOp.POW:
702 assert len(args) == 2
703 return RegPow(args[0], args[1])
704 if op == RegWiseOp.LSH:
705 assert len(args) == 2
706 return RegLsh(args[0], args[1])
707 if op == RegWiseOp.RSH:
708 assert len(args) == 2
709 return RegRsh(args[0], args[1])
710 if op == RegWiseOp.EQ:
711 assert len(args) == 2
712 return RegEq(args[0], args[1])
713 if op == RegWiseOp.NEQ:
714 assert len(args) == 2
715 return RegNeq(args[0], args[1])
716 if op == RegWiseOp.LT:
717 assert len(args) == 2
718 return RegLt(args[0], args[1])
719 if op == RegWiseOp.GT:
720 assert len(args) == 2
721 return RegGt(args[0], args[1])
722 if op == RegWiseOp.LEQ:
723 assert len(args) == 2
724 return RegLeq(args[0], args[1])
725 if op == RegWiseOp.GEQ: 725 ↛ 726line 725 didn't jump to line 726 because the condition on line 725 was never true
726 assert len(args) == 2
727 return RegGeq(args[0], args[1])
728 if op == RegWiseOp.NOT: 728 ↛ 731line 728 didn't jump to line 731 because the condition on line 728 was always true
729 assert len(args) == 1
730 return RegNot(args[0])
731 raise ValueError("op type not supported")
734def create_logic_exp(op: Ops, args: Sequence[ArgType]) -> LogicExp:
735 if isinstance(op, BitWiseOp):
736 bit_args = []
737 for arg in args:
738 assert isinstance(arg, (BitLogicExp, Bit, Constant))
739 bit_args.append(arg)
740 return create_bit_logic_exp(op, bit_args)
741 assert isinstance(op, RegWiseOp)
742 reg_args = []
743 for arg in args:
744 assert isinstance(arg, (RegLogicExp, BitRegister, Constant))
745 reg_args.append(arg)
746 return create_reg_logic_exp(op, reg_args)
749def create_predicate_exp(op: Ops, args: Sequence[ArgType]) -> PredicateExp:
750 if op == BitWiseOp.EQ:
751 assert len(args) == 2
752 assert isinstance(args[0], (BitLogicExp, Bit, int))
753 assert isinstance(args[1], (BitLogicExp, Bit, int))
754 return BitEq(args[0], args[1])
755 if op == BitWiseOp.NEQ: 755 ↛ 756line 755 didn't jump to line 756 because the condition on line 755 was never true
756 assert len(args) == 2
757 assert isinstance(args[0], (BitLogicExp, Bit, int))
758 assert isinstance(args[1], (BitLogicExp, Bit, int))
759 return BitNeq(args[0], args[1])
760 if op == RegWiseOp.EQ:
761 assert len(args) == 2
762 assert isinstance(args[0], (RegLogicExp, BitRegister, int))
763 assert isinstance(args[1], (RegLogicExp, BitRegister, int))
764 return RegEq(args[0], args[1])
765 if op == RegWiseOp.NEQ:
766 assert len(args) == 2
767 assert isinstance(args[0], (RegLogicExp, BitRegister, int))
768 assert isinstance(args[1], (RegLogicExp, BitRegister, int))
769 return RegNeq(args[0], args[1])
770 if op == RegWiseOp.LT:
771 assert len(args) == 2
772 assert isinstance(args[0], (RegLogicExp, BitRegister, int))
773 assert isinstance(args[1], (RegLogicExp, BitRegister, int))
774 return RegLt(args[0], args[1])
775 if op == RegWiseOp.GT:
776 assert len(args) == 2
777 assert isinstance(args[0], (RegLogicExp, BitRegister, int))
778 assert isinstance(args[1], (RegLogicExp, BitRegister, int))
779 return RegGt(args[0], args[1])
780 if op == RegWiseOp.LEQ:
781 assert len(args) == 2
782 assert isinstance(args[0], (RegLogicExp, BitRegister, int))
783 assert isinstance(args[1], (RegLogicExp, BitRegister, int))
784 return RegLeq(args[0], args[1])
785 if op == RegWiseOp.GEQ: 785 ↛ 790line 785 didn't jump to line 790 because the condition on line 785 was always true
786 assert len(args) == 2
787 assert isinstance(args[0], (RegLogicExp, BitRegister, int))
788 assert isinstance(args[1], (RegLogicExp, BitRegister, int))
789 return RegGeq(args[0], args[1])
790 raise ValueError("op type not supported")