Newer
Older
Angus Lothian
committed
Contains some of the most commonly used mathematical operations.
from typing import Dict, Optional
from numpy import abs as np_abs
from numpy import conjugate, sqrt
Angus Lothian
committed
from b_asic.graph_component import Name, TypeName
from b_asic.operation import AbstractOperation
from b_asic.port import SignalSourceProvider
Angus Lothian
committed
Gives a specified value that remains constant for every iteration.
.. math:: y = \text{value}
Parameters
==========
value : Number, default: 0
The constant value.
name : Name, optional
Operation name.
__slots__ = ("_value", "_name")
_value: Num
_name: Name
Angus Lothian
committed
"""Construct a Constant operation with the given value."""
super().__init__(
input_count=0,
output_count=1,
Angus Lothian
committed
self.set_param("value", value)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
def evaluate(self):
return self.param("value")
@property
Angus Lothian
committed
"""Get the constant value of this operation."""
return self.param("value")
@value.setter
Angus Lothian
committed
"""Set the constant value of this operation."""
@property
def latency(self) -> int:
return self.latency_offsets["out0"]
def __repr__(self) -> str:
return f"Constant({self.value})"
def __str__(self) -> str:
return f"{self.value}"
Simon Bjurek
committed
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
def get_plot_coordinates(
self,
) -> tuple[tuple[tuple[float, float], ...], tuple[tuple[float, float], ...]]:
# Doc-string inherited
return (
(
(-0.5, 0),
(-0.5, 1),
(-0.25, 1),
(0, 0.5),
(-0.25, 0),
(-0.5, 0),
),
(
(-0.5, 0),
(-0.5, 1),
(-0.25, 1),
(0, 0.5),
(-0.25, 0),
(-0.5, 0),
),
)
def get_input_coordinates(self) -> tuple[tuple[float, float], ...]:
# doc-string inherited
return tuple()
def get_output_coordinates(self) -> tuple[tuple[float, float], ...]:
# doc-string inherited
return ((0, 0.5),)
Angus Lothian
committed
Gives the result of adding two inputs.
.. math:: y = x_0 + x_1
Parameters
==========
src0, src1 : SignalSourceProvider, optional
The two signals to add.
name : Name, optional
Operation name.
latency : int, optional
Operation latency (delay from input to output in time units).
latency_offsets : dict[str, int], optional
Used if inputs have different arrival times, e.g.,
``{"in0": 0, "in1": 1}`` which corresponds to *src1* arriving one
time unit later than *src0*. If not provided and *latency* is
provided, set to zero if not explicitly provided. So the previous
example can be written as ``{"in1": 1}`` only.
execution_time : int, optional
Operation execution time (time units before operator can be
reused).
See also
========
AddSub
Angus Lothian
committed
"""
__slots__ = (
"_src0",
"_src1",
"_name",
"_latency",
"_latency_offsets",
"_execution_time",
)
_src0: Optional[SignalSourceProvider]
_src1: Optional[SignalSourceProvider]
_name: Name
_latency: Optional[int]
_latency_offsets: Optional[Dict[str, int]]
_execution_time: Optional[int]
is_swappable = True
def __init__(
self,
src0: Optional[SignalSourceProvider] = None,
src1: Optional[SignalSourceProvider] = None,
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
"""
Construct an Addition operation.
"""
super().__init__(
input_count=2,
output_count=1,
input_sources=[src0, src1],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
def evaluate(self, a, b):
return a + b
class Subtraction(AbstractOperation):
Angus Lothian
committed
Gives the result of subtracting the second input from the first one.
.. math:: y = x_0 - x_1
Parameters
==========
src0, src1 : SignalSourceProvider, optional
The two signals to subtract.
name : Name, optional
Operation name.
latency : int, optional
Operation latency (delay from input to output in time units).
latency_offsets : dict[str, int], optional
Used if inputs have different arrival times, e.g.,
``{"in0": 0, "in1": 1}`` which corresponds to *src1* arriving one
time unit later than *src0*. If not provided and *latency* is
provided, set to zero if not explicitly provided. So the previous
example can be written as ``{"in1": 1}`` only.
execution_time : int, optional
Operation execution time (time units before operator can be
reused).
See also
========
AddSub
__slots__ = (
"_src0",
"_src1",
"_name",
"_latency",
"_latency_offsets",
"_execution_time",
)
_src0: Optional[SignalSourceProvider]
_src1: Optional[SignalSourceProvider]
_name: Name
_latency: Optional[int]
_latency_offsets: Optional[Dict[str, int]]
_execution_time: Optional[int]
def __init__(
self,
src0: Optional[SignalSourceProvider] = None,
src1: Optional[SignalSourceProvider] = None,
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
Angus Lothian
committed
"""Construct a Subtraction operation."""
super().__init__(
input_count=2,
output_count=1,
input_sources=[src0, src1],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
def evaluate(self, a, b):
return a - b
class AddSub(AbstractOperation):
Two-input addition or subtraction operation.
Gives the result of adding or subtracting two inputs.
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
.. math::
y = \begin{cases}
x_0 + x_1,& \text{is_add} = \text{True}\\
x_0 - x_1,& \text{is_add} = \text{False}
\end{cases}
This is used to later map additions and subtractions to the same
operator.
Parameters
==========
is_add : bool, default: True
If True, the operation is an addition, if False, a subtraction.
src0, src1 : SignalSourceProvider, optional
The two signals to add or subtract.
name : Name, optional
Operation name.
latency : int, optional
Operation latency (delay from input to output in time units).
latency_offsets : dict[str, int], optional
Used if inputs have different arrival times, e.g.,
``{"in0": 0, "in1": 1}`` which corresponds to *src1* arriving one
time unit later than *src0*. If not provided and *latency* is
provided, set to zero if not explicitly provided. So the previous
example can be written as ``{"in1": 1}`` only.
execution_time : int, optional
Operation execution time (time units before operator can be
reused).
See also
========
Addition, Subtraction
__slots__ = (
"_is_add",
"_src0",
"_src1",
"_name",
"_latency",
"_latency_offsets",
"_execution_time",
)
_is_add: bool
_src0: Optional[SignalSourceProvider]
_src1: Optional[SignalSourceProvider]
_name: Name
_latency: Optional[int]
_latency_offsets: Optional[Dict[str, int]]
_execution_time: Optional[int]
def __init__(
self,
is_add: bool = True,
src0: Optional[SignalSourceProvider] = None,
src1: Optional[SignalSourceProvider] = None,
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
"""Construct an Addition/Subtraction operation."""
super().__init__(
input_count=2,
output_count=1,
input_sources=[src0, src1],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
self.set_param("is_add", is_add)
@classmethod
def type_name(cls) -> TypeName:
def evaluate(self, a, b):
return a + b if self.is_add else a - b
@property
def is_add(self) -> bool:
"""Get if operation is an addition."""
return self.param("is_add")
@is_add.setter
def is_add(self, is_add: bool) -> None:
"""Set if operation is an addition."""
@property
def is_swappable(self) -> bool:
return self.is_add
Angus Lothian
committed
Gives the result of multiplying two inputs.
.. math:: y = x_0 \times x_1
Parameters
==========
src0, src1 : SignalSourceProvider, optional
The two signals to multiply.
name : Name, optional
Operation name.
latency : int, optional
Operation latency (delay from input to output in time units).
latency_offsets : dict[str, int], optional
Used if inputs have different arrival times or if the inputs should arrive
after the operator has stared. For example, ``{"in0": 0, "in1": 1}`` which
corresponds to *src1* arriving one time unit later than *src0* and one time
unit later than the operator starts. If not provided and *latency* is provided,
set to zero. Hence, the previous example can be written as ``{"in1": 1}``
only.
execution_time : int, optional
Operation execution time (time units before operator can be reused).
========
ConstantMultiplication
__slots__ = (
"_src0",
"_src1",
"_name",
"_latency",
"_latency_offsets",
"_execution_time",
)
_src0: Optional[SignalSourceProvider]
_src1: Optional[SignalSourceProvider]
_name: Name
_latency: Optional[int]
_latency_offsets: Optional[Dict[str, int]]
_execution_time: Optional[int]
is_swappable = True
def __init__(
self,
src0: Optional[SignalSourceProvider] = None,
src1: Optional[SignalSourceProvider] = None,
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
Angus Lothian
committed
"""Construct a Multiplication operation."""
super().__init__(
input_count=2,
output_count=1,
input_sources=[src0, src1],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
def evaluate(self, a, b):
return a * b
@property
def is_linear(self) -> bool:
return any(
input_.connected_source.operation.is_constant for input_ in self.inputs
Angus Lothian
committed
Gives the result of dividing the first input by the second one.
.. math:: y = \frac{x_0}{x_1}
Parameters
==========
src0, src1 : SignalSourceProvider, optional
The two signals to divide.
name : Name, optional
Operation name.
latency : int, optional
Operation latency (delay from input to output in time units).
latency_offsets : dict[str, int], optional
Used if inputs have different arrival times or if the inputs should arrive
after the operator has stared. For example, ``{"in0": 0, "in1": 1}`` which
corresponds to *src1* arriving one time unit later than *src0* and one time
unit later than the operator starts. If not provided and *latency* is provided,
set to zero. Hence, the previous example can be written as ``{"in1": 1}``
only.
execution_time : int, optional
Operation execution time (time units before operator can be reused).
See Also
Angus Lothian
committed
"""
__slots__ = (
"_src0",
"_src1",
"_name",
"_latency",
"_latency_offsets",
"_execution_time",
)
_src0: Optional[SignalSourceProvider]
_src1: Optional[SignalSourceProvider]
_name: Name
_latency: Optional[int]
_latency_offsets: Optional[Dict[str, int]]
_execution_time: Optional[int]
def __init__(
self,
src0: Optional[SignalSourceProvider] = None,
src1: Optional[SignalSourceProvider] = None,
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
Angus Lothian
committed
"""Construct a Division operation."""
super().__init__(
input_count=2,
output_count=1,
input_sources=[src0, src1],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
Angus Lothian
committed
def evaluate(self, a, b):
return a / b
@property
def is_linear(self) -> bool:
return self.input(1).connected_source.operation.is_constant
Angus Lothian
committed
class Min(AbstractOperation):
Angus Lothian
committed
Gives the minimum value of two inputs.
.. math:: y = \min\{x_0 , x_1\}
.. note:: Only real-valued numbers are supported.
Parameters
==========
src0, src1 : SignalSourceProvider, optional
The two signals to determine the min of.
name : Name, optional
Operation name.
latency : int, optional
Operation latency (delay from input to output in time units).
latency_offsets : dict[str, int], optional
Used if inputs have different arrival times or if the inputs should arrive
after the operator has stared. For example, ``{"in0": 0, "in1": 1}`` which
corresponds to *src1* arriving one time unit later than *src0* and one time
unit later than the operator starts. If not provided and *latency* is provided,
set to zero. Hence, the previous example can be written as ``{"in1": 1}``
only.
execution_time : int, optional
Operation execution time (time units before operator can be reused).
See Also
__slots__ = (
"_src0",
"_src1",
"_name",
"_latency",
"_latency_offsets",
"_execution_time",
)
_src0: Optional[SignalSourceProvider]
_src1: Optional[SignalSourceProvider]
_name: Name
_latency: Optional[int]
_latency_offsets: Optional[Dict[str, int]]
_execution_time: Optional[int]
is_swappable = True
def __init__(
self,
src0: Optional[SignalSourceProvider] = None,
src1: Optional[SignalSourceProvider] = None,
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
Angus Lothian
committed
"""Construct a Min operation."""
super().__init__(
input_count=2,
output_count=1,
input_sources=[src0, src1],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
Angus Lothian
committed
def evaluate(self, a, b):
if isinstance(a, complex) or isinstance(b, complex):
raise ValueError("core_operations.Min does not support complex numbers.")
Angus Lothian
committed
return a if a < b else b
Angus Lothian
committed
Gives the maximum value of two inputs.
.. math:: y = \max\{x_0 , x_1\}
.. note:: Only real-valued numbers are supported.
Parameters
==========
src0, src1 : SignalSourceProvider, optional
The two signals to determine the min of.
name : Name, optional
Operation name.
latency : int, optional
Operation latency (delay from input to output in time units).
latency_offsets : dict[str, int], optional
Used if inputs have different arrival times or if the inputs should arrive
after the operator has stared. For example, ``{"in0": 0, "in1": 1}`` which
corresponds to *src1* arriving one time unit later than *src0* and one time
unit later than the operator starts. If not provided and *latency* is provided,
set to zero. Hence, the previous example can be written as ``{"in1": 1}``
only.
execution_time : int, optional
Operation execution time (time units before operator can be reused).
See Also
__slots__ = (
"_src0",
"_src1",
"_name",
"_latency",
"_latency_offsets",
"_execution_time",
)
_src0: Optional[SignalSourceProvider]
_src1: Optional[SignalSourceProvider]
_name: Name
_latency: Optional[int]
_latency_offsets: Optional[Dict[str, int]]
_execution_time: Optional[int]
is_swappable = True
def __init__(
self,
src0: Optional[SignalSourceProvider] = None,
src1: Optional[SignalSourceProvider] = None,
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
Angus Lothian
committed
"""Construct a Max operation."""
super().__init__(
input_count=2,
output_count=1,
input_sources=[src0, src1],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
if isinstance(a, complex) or isinstance(b, complex):
raise ValueError("core_operations.Max does not support complex numbers.")
Angus Lothian
committed
class SquareRoot(AbstractOperation):
Angus Lothian
committed
Gives the square root of its input.
.. math:: y = \sqrt{x}
Parameters
----------
src0 : :class:`~b_asic.port.SignalSourceProvider`, optional
The signal to compute the square root of.
name : Name, optional
Operation name.
latency : int, optional
Operation latency (delay from input to output in time units).
latency_offsets : dict[str, int], optional
Used if input arrives later than when the operator starts, e.g.,
``{"in0": 0`` which corresponds to *src0* arriving one time unit after the
operator starts. If not provided and *latency* is provided, set to zero.
execution_time : int, optional
Operation execution time (time units before operator can be reused).
__slots__ = ("_src0", "_name", "_latency", "_latency_offsets", "_execution_time")
_src0: Optional[SignalSourceProvider]
_name: Name
_latency: Optional[int]
_latency_offsets: Optional[Dict[str, int]]
_execution_time: Optional[int]
def __init__(
self,
src0: Optional[SignalSourceProvider] = None,
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
Angus Lothian
committed
"""Construct a SquareRoot operation."""
super().__init__(
input_count=1,
output_count=1,
input_sources=[src0],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
Angus Lothian
committed
def evaluate(self, a):
return sqrt(complex(a))
Angus Lothian
committed
class ComplexConjugate(AbstractOperation):
Angus Lothian
committed
Gives the complex conjugate of its input.
.. math:: y = x^*
Parameters
----------
src0 : :class:`~b_asic.port.SignalSourceProvider`, optional
The signal to compute the complex conjugate of.
name : Name, optional
Operation name.
latency : int, optional
Operation latency (delay from input to output in time units).
latency_offsets : dict[str, int], optional
Used if input arrives later than when the operator starts, e.g.,
``{"in0": 0`` which corresponds to *src0* arriving one time unit after the
operator starts. If not provided and *latency* is provided, set to zero.
execution_time : int, optional
Operation execution time (time units before operator can be reused).
__slots__ = ("_src0", "_name", "_latency", "_latency_offsets", "_execution_time")
_src0: Optional[SignalSourceProvider]
_name: Name
_latency: Optional[int]
_latency_offsets: Optional[Dict[str, int]]
_execution_time: Optional[int]
def __init__(
self,
src0: Optional[SignalSourceProvider] = None,
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
Angus Lothian
committed
"""Construct a ComplexConjugate operation."""
super().__init__(
input_count=1,
output_count=1,
input_sources=[src0],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
Angus Lothian
committed
return conjugate(a)
Angus Lothian
committed
class Absolute(AbstractOperation):
Angus Lothian
committed
Gives the absolute value of its input.
.. math:: y = |x|
Parameters
----------
src0 : :class:`~b_asic.port.SignalSourceProvider`, optional
The signal to compute the absolute value of.
name : Name, optional
Operation name.
latency : int, optional
Operation latency (delay from input to output in time units).
latency_offsets : dict[str, int], optional
Used if input arrives later than when the operator starts, e.g.,
``{"in0": 0`` which corresponds to *src0* arriving one time unit after the
operator starts. If not provided and *latency* is provided, set to zero.
execution_time : int, optional
Operation execution time (time units before operator can be reused).
__slots__ = ("_src0", "_name", "_latency", "_latency_offsets", "_execution_time")
_src0: Optional[SignalSourceProvider]
_name: Name
_latency: Optional[int]
_latency_offsets: Optional[Dict[str, int]]
_execution_time: Optional[int]
def __init__(
self,
src0: Optional[SignalSourceProvider] = None,
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
Angus Lothian
committed
"""Construct an Absolute operation."""
super().__init__(
input_count=1,
output_count=1,
input_sources=[src0],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
Angus Lothian
committed
return np_abs(a)
Angus Lothian
committed
class ConstantMultiplication(AbstractOperation):
Angus Lothian
committed
Gives the result of multiplying its input by a specified value.
.. math:: y = x_0 \times \text{value}
Parameters
----------
value : int
Value to multiply with.
src0 : :class:`~b_asic.port.SignalSourceProvider`, optional
The signal to multiply.
name : Name, optional
Operation name.
latency : int, optional
Operation latency (delay from input to output in time units).
latency_offsets : dict[str, int], optional
Used if input arrives later than when the operator starts, e.g.,
``{"in0": 0`` which corresponds to *src0* arriving one time unit after the
operator starts. If not provided and *latency* is provided, set to zero.
execution_time : int, optional
Operation execution time (time units before operator can be reused).
See Also
--------
Multiplication
__slots__ = (
"_value",
"_src0",
"_name",
"_latency",
"_latency_offsets",
"_execution_time",
)
_value: Num
_src0: Optional[SignalSourceProvider]
_name: Name
_latency: Optional[int]
_latency_offsets: Optional[Dict[str, int]]
_execution_time: Optional[int]
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
"""Construct a ConstantMultiplication operation with the given value."""
super().__init__(
input_count=1,
output_count=1,
input_sources=[src0],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
Angus Lothian
committed
self.set_param("value", value)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
Angus Lothian
committed
return a * self.param("value")
Angus Lothian
committed
"""Get the constant value of this operation."""
return self.param("value")
@value.setter
Angus Lothian
committed
"""Set the constant value of this operation."""
Angus Lothian
committed
class Butterfly(AbstractOperation):
Angus Lothian
committed
Gives the result of adding its two inputs, as well as the result of subtracting the
second input from the first one. This corresponds to a 2-point DFT.
Angus Lothian
committed
.. math::
\begin{eqnarray}
y_0 & = & x_0 + x_1\\
y_1 & = & x_0 - x_1
\end{eqnarray}
Parameters
==========
src0, src1 : SignalSourceProvider, optional
The two signals to compute the 2-point DFT of.
name : Name, optional
Operation name.
latency : int, optional
Operation latency (delay from input to output in time units).
latency_offsets : dict[str, int], optional
Used if inputs have different arrival times or if the inputs should arrive
after the operator has stared. For example, ``{"in0": 0, "in1": 1}`` which
corresponds to *src1* arriving one time unit later than *src0* and one time
unit later than the operator starts. If not provided and *latency* is provided,
set to zero. Hence, the previous example can be written as ``{"in1": 1}``
only.
execution_time : int, optional
Operation execution time (time units before operator can be reused).