Newer
Older
Angus Lothian
committed
"""B-ASIC Core Operations Module.
Contains some of the most commonly used mathematical operations.
Angus Lothian
committed
from typing import Optional, Dict
from numpy import conjugate, sqrt, abs as np_abs
Angus Lothian
committed
from b_asic.port import SignalSourceProvider, InputPort, OutputPort
from b_asic.operation import AbstractOperation
from b_asic.graph_component import Name, TypeName
class Constant(AbstractOperation):
"""Constant value operation.
Angus Lothian
committed
Gives a specified value that remains constant for every iteration.
output(0): self.param("value")
def __init__(self, value: Number = 0, name: Name = ""):
Angus Lothian
committed
"""Construct a Constant operation with the given value."""
super().__init__(input_count=0, output_count=1, name=name, latency_offsets={'out0' : 0})
Angus Lothian
committed
self.set_param("value", value)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
return "c"
def evaluate(self):
return self.param("value")
@property
Angus Lothian
committed
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)
class Addition(AbstractOperation):
"""Binary addition operation.
Angus Lothian
committed
Gives the result of adding two inputs.
output(0): input(0) + input(1)
"""
Angus Lothian
committed
def __init__(self, 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)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
return "add"
def evaluate(self, a, b):
return a + b
class Subtraction(AbstractOperation):
"""Binary subtraction operation.
Angus Lothian
committed
Gives the result of subtracting the second input from the first one.
output(0): input(0) - input(1)
Angus Lothian
committed
def __init__(self, src0: Optional[SignalSourceProvider] = None, src1: Optional[SignalSourceProvider] = None, name: Name = "", latency: Optional[int] = None, latency_offsets: Optional[Dict[str, int]] = None):
"""Construct a Subtraction operation."""
super().__init__(input_count=2, output_count=1, name=name, input_sources=[src0, src1],
latency=latency, latency_offsets=latency_offsets)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
return "sub"
def evaluate(self, a, b):
return a - b
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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.
Angus Lothian
committed
Gives the result of multiplying two inputs.
output(0): input(0) * input(1)
Angus Lothian
committed
def __init__(self, src0: Optional[SignalSourceProvider] = None, src1: Optional[SignalSourceProvider] = None, name: Name = "", latency: Optional[int] = None, latency_offsets: Optional[Dict[str, int]] = None):
"""Construct a Multiplication operation."""
super().__init__(input_count=2, output_count=1, name=name, input_sources=[src0, src1],
latency=latency, latency_offsets=latency_offsets)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
return "mul"
def evaluate(self, a, b):
return a * b
class Division(AbstractOperation):
"""Binary division operation.
Angus Lothian
committed
Gives the result of dividing the first input by the second one.
Angus Lothian
committed
output(0): input(0) / input(1)
"""
Angus Lothian
committed
def __init__(self, src0: Optional[SignalSourceProvider] = None, src1: Optional[SignalSourceProvider] = None, name: Name = "", latency: Optional[int] = None, latency_offsets: Optional[Dict[str, int]] = None):
"""Construct a Division operation."""
super().__init__(input_count=2, output_count=1, name=name, input_sources=[src0, src1],
latency=latency, latency_offsets=latency_offsets)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
Angus Lothian
committed
def evaluate(self, a, b):
return a / b
Angus Lothian
committed
class Min(AbstractOperation):
"""Binary min operation.
Angus Lothian
committed
Gives the minimum value of two inputs.
NOTE: Non-real numbers are not supported.
Angus Lothian
committed
output(0): min(input(0), input(1))
Angus Lothian
committed
def __init__(self, src0: Optional[SignalSourceProvider] = None, src1: Optional[SignalSourceProvider] = None, name: Name = "", latency: Optional[int] = None, latency_offsets: Optional[Dict[str, int]] = None):
"""Construct a Min operation."""
super().__init__(input_count=2, output_count=1, name=name, input_sources=[src0, src1],
latency=latency, latency_offsets=latency_offsets)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
return "min"
Angus Lothian
committed
def evaluate(self, a, b):
assert not isinstance(a, complex) and not isinstance(b, complex), \
("core_operations.Min does not support complex numbers.")
return a if a < b else b
class Max(AbstractOperation):
"""Binary max operation.
Angus Lothian
committed
Gives the maximum value of two inputs.
NOTE: Non-real numbers are not supported.
output(0): max(input(0), input(1))
Angus Lothian
committed
def __init__(self, src0: Optional[SignalSourceProvider] = None, src1: Optional[SignalSourceProvider] = None, name: Name = "", latency: Optional[int] = None, latency_offsets: Optional[Dict[str, int]] = None):
"""Construct a Max operation."""
super().__init__(input_count=2, output_count=1, name=name, input_sources=[src0, src1],
latency=latency, latency_offsets=latency_offsets)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
return "max"
def evaluate(self, a, b):
assert not isinstance(a, complex) and not isinstance(b, complex), \
("core_operations.Max does not support complex numbers.")
return a if a > b else b
Angus Lothian
committed
class SquareRoot(AbstractOperation):
"""Square root operation.
Angus Lothian
committed
Gives the square root of its input.
output(0): sqrt(input(0))
Angus Lothian
committed
def __init__(self, src0: Optional[SignalSourceProvider] = None, name: Name = "", latency: Optional[int] = None, latency_offsets: Optional[Dict[str, int]] = None):
"""Construct a SquareRoot operation."""
super().__init__(input_count=1, output_count=1, name=name, input_sources=[src0],
latency=latency, latency_offsets=latency_offsets)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
return "sqrt"
Angus Lothian
committed
def evaluate(self, a):
return sqrt(complex(a))
Angus Lothian
committed
class ComplexConjugate(AbstractOperation):
"""Complex conjugate operation.
Angus Lothian
committed
Gives the complex conjugate of its input.
output(0): conj(input(0))
Angus Lothian
committed
def __init__(self, src0: Optional[SignalSourceProvider] = None, name: Name = "", latency: Optional[int] = None, latency_offsets: Optional[Dict[str, int]] = None):
"""Construct a ComplexConjugate operation."""
super().__init__(input_count=1, output_count=1, name=name, input_sources=[src0],
latency=latency, latency_offsets=latency_offsets)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
return "conj"
Angus Lothian
committed
return conjugate(a)
Angus Lothian
committed
class Absolute(AbstractOperation):
"""Absolute value operation.
Angus Lothian
committed
Gives the absolute value of its input.
output(0): abs(input(0))
Angus Lothian
committed
def __init__(self, src0: Optional[SignalSourceProvider] = None, name: Name = "", latency: Optional[int] = None, latency_offsets: Optional[Dict[str, int]] = None):
"""Construct an Absolute operation."""
super().__init__(input_count=1, output_count=1, name=name, input_sources=[src0],
latency=latency, latency_offsets=latency_offsets)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
return "abs"
Angus Lothian
committed
return np_abs(a)
Angus Lothian
committed
class ConstantMultiplication(AbstractOperation):
"""Constant multiplication operation.
Gives the result of multiplying its input by a specified value.
Angus Lothian
committed
output(0): self.param("value") * input(0)
Angus Lothian
committed
def __init__(self, value: Number = 0, src0: Optional[SignalSourceProvider] = None, name: Name = "", latency: Optional[int] = None, latency_offsets: Optional[Dict[str, int]] = None):
"""Construct a ConstantMultiplication operation with the given value."""
super().__init__(input_count=1, output_count=1, name=name, input_sources=[src0],
latency=latency, latency_offsets=latency_offsets)
self.set_param("value", value)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
return "cmul"
Angus Lothian
committed
return a * self.param("value")
Angus Lothian
committed
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)
Angus Lothian
committed
class Butterfly(AbstractOperation):
"""Butterfly operation.
Gives the result of adding its two inputs, as well as the result of
subtracting the second input from the first one.
output(0): input(0) + input(1)
output(1): input(0) - input(1)
Angus Lothian
committed
def __init__(self, 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)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
return "bfly"
Angus Lothian
committed
def evaluate(self, a, b):
return a + b, a - b
Angus Lothian
committed
class MAD(AbstractOperation):
"""Multiply-add operation.
Angus Lothian
committed
Gives the result of multiplying the first input by the second input and
then adding the third input.
Angus Lothian
committed
output(0): (input(0) * input(1)) + input(2)
"""
Angus Lothian
committed
def __init__(self, src0: Optional[SignalSourceProvider] = None, src1: Optional[SignalSourceProvider] = None, src2: Optional[SignalSourceProvider] = None, name: Name = "", latency: Optional[int] = None, latency_offsets: Optional[Dict[str, int]] = None):
"""Construct a MAD operation."""
super().__init__(input_count=3, output_count=1, name=name, input_sources=[src0, src1, src2],
latency=latency, latency_offsets=latency_offsets)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
return "mad"
Angus Lothian
committed
def evaluate(self, a, b, c):
return a * b + c
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
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)