diff --git a/b_asic/core_operations.py b/b_asic/core_operations.py index 6459948ca58a879a7853ea2e5846509d567ee79e..b89ade6214694f00c6500866427111b7571ff789 100644 --- a/b_asic/core_operations.py +++ b/b_asic/core_operations.py @@ -85,6 +85,39 @@ class Subtraction(AbstractOperation): return a - b +class AddSub(AbstractOperation): + """Two-input addition or subtraction operation. + + Gives the result of adding or subtracting two inputs. + + output(0): input(0) + input(1) if is_add = True + output(0): input(0) - input(1) if is_add = False + """ + + def __init__(self, is_add: bool = True, src0: Optional[SignalSourceProvider] = None, src1: Optional[SignalSourceProvider] = None, name: Name = "", latency: Optional[int] = None, latency_offsets: Optional[Dict[str, int]] = None): + """Construct an Addition operation.""" + super().__init__(input_count=2, output_count=1, name=name, input_sources=[src0, src1], + latency=latency, latency_offsets=latency_offsets) + self.set_param("is_add", is_add) + + @classmethod + def type_name(cls) -> TypeName: + return "addsub" + + def evaluate(self, a, b): + return a + b if self.is_add else a - b + + @property + def is_add(self) -> Number: + """Get if operation is add.""" + return self.param("is_add") + + @is_add.setter + def is_add(self, is_add: bool) -> None: + """Set if operation is add.""" + return self.set_param("is_add", is_add) + + class Multiplication(AbstractOperation): """Binary multiplication operation. @@ -313,3 +346,35 @@ class MAD(AbstractOperation): def evaluate(self, a, b, c): return a * b + c + + +class SymmetricTwoportAdaptor(AbstractOperation): + """Symmetric twoport-adaptor operation. + + output(0): input(1) + value*(input(1) - input(0) + output(1): input(0) + value*(input(1) - input(0) + """ + + def __init__(self, value: Number = 0, src0: Optional[SignalSourceProvider] = None, src1: Optional[SignalSourceProvider] = None, name: Name = "", latency: Optional[int] = None, latency_offsets: Optional[Dict[str, int]] = None): + """Construct a Butterfly operation.""" + super().__init__(input_count=2, output_count=2, name=name, input_sources=[src0, src1], + latency=latency, latency_offsets=latency_offsets) + self.set_param("value", value) + + @classmethod + def type_name(cls) -> TypeName: + return "sym2p" + + def evaluate(self, a, b): + tmp = self.value*(b - a) + return b + tmp, a + tmp + + @property + def value(self) -> Number: + """Get the constant value of this operation.""" + return self.param("value") + + @value.setter + def value(self, value: Number) -> None: + """Set the constant value of this operation.""" + return self.set_param("value", value) diff --git a/test/test_core_operations.py b/test/test_core_operations.py index 6a0493c60965579bd843e0b514bd7f9b9a0e4707..f074e8356f4e5fc3dec654f25f5441a0025cea68 100644 --- a/test/test_core_operations.py +++ b/test/test_core_operations.py @@ -2,9 +2,10 @@ B-ASIC test suite for the core operations. """ -from b_asic import \ - Constant, Addition, Subtraction, Multiplication, ConstantMultiplication, Division, \ - SquareRoot, ComplexConjugate, Max, Min, Absolute, Butterfly +from b_asic import (Constant, Addition, Subtraction, AddSub, Multiplication, + ConstantMultiplication, Division, SquareRoot, + ComplexConjugate, Max, Min, Absolute, Butterfly, + SymmetricTwoportAdaptor) class TestConstant: def test_constant_positive(self): @@ -48,6 +49,32 @@ class TestSubtraction: assert test_operation.evaluate_output(0, [3+5j, 4+6j]) == -1-1j +class TestAddSub: + def test_addition_positive(self): + test_operation = AddSub(is_add=True) + assert test_operation.evaluate_output(0, [3, 5]) == 8 + + def test_addition_negative(self): + test_operation = AddSub(is_add=True) + assert test_operation.evaluate_output(0, [-3, -5]) == -8 + + def test_addition_complex(self): + test_operation = AddSub(is_add=True) + assert test_operation.evaluate_output(0, [3+5j, 4+6j]) == 7+11j + + def test_addsub_subtraction_positive(self): + test_operation = AddSub(is_add=False) + assert test_operation.evaluate_output(0, [5, 3]) == 2 + + def test_addsub_subtraction_negative(self): + test_operation = AddSub(is_add=False) + assert test_operation.evaluate_output(0, [-5, -3]) == -2 + + def test_addsub_subtraction_complex(self): + test_operation = AddSub(is_add=False) + assert test_operation.evaluate_output(0, [3+5j, 4+6j]) == -1-1j + + class TestMultiplication: def test_multiplication_positive(self): test_operation = Multiplication() @@ -165,6 +192,23 @@ class TestButterfly: assert test_operation.evaluate_output(1, [2+1j, 3-2j]) == -1+3j +class TestSymmetricTwoportAdaptor: + def test_symmetrictwoportadaptor_positive(self): + test_operation = SymmetricTwoportAdaptor(0.5) + assert test_operation.evaluate_output(0, [2, 3]) == 3.5 + assert test_operation.evaluate_output(1, [2, 3]) == 2.5 + + def test_symmetrictwoportadaptor_negative(self): + test_operation = SymmetricTwoportAdaptor(0.5) + assert test_operation.evaluate_output(0, [-2, -3]) == -3.5 + assert test_operation.evaluate_output(1, [-2, -3]) == -2.5 + + def test_symmetrictwoportadaptor_complex(self): + test_operation = SymmetricTwoportAdaptor(0.5) + assert test_operation.evaluate_output(0, [2+1j, 3-2j]) == 3.5-3.5j + assert test_operation.evaluate_output(1, [2+1j, 3-2j]) == 2.5-0.5j + + class TestDepends: def test_depends_addition(self): add1 = Addition()