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.
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}"
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
"""
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
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.
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
.. 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
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
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
"""
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
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
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).
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).
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).
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
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).
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 Butterfly operation."""
super().__init__(
input_count=2,
output_count=2,
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, a - b
Angus Lothian
committed
class MAD(AbstractOperation):
Angus Lothian
committed
Gives the result of multiplying the first input by the second input and
then adding the third input.
.. math:: y = x_0 \times x_1 + x_2
Parameters
==========
src0, src1, src2 : SignalSourceProvider, optional
The three signals to determine the multiply-add operation 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": 0, "in2": 2}``
which corresponds to *src2*, i.e., the term to be added, arriving two time
units later than *src0* and *src1*. 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
--------
Multiplication
Addition
Angus Lothian
committed
"""
is_swappable = True
def __init__(
self,
src0: Optional[SignalSourceProvider] = None,
src1: Optional[SignalSourceProvider] = None,
src2: Optional[SignalSourceProvider] = None,
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
Angus Lothian
committed
"""Construct a MAD operation."""
super().__init__(
input_count=3,
output_count=1,
input_sources=[src0, src1, src2],
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, c):
return a * b + c
@property
def is_linear(self) -> bool:
return (
self.input(0).connected_source.operation.is_constant
or self.input(1).connected_source.operation.is_constant
)
def swap_io(self) -> None:
self._input_ports = [
self._input_ports[1],
self._input_ports[0],
self._input_ports[2],
]
for i, p in enumerate(self._input_ports):
p._index = i
class SymmetricTwoportAdaptor(AbstractOperation):
.. math::
\begin{eqnarray}
y_0 & = & x_1 + \text{value}\times\left(x_1 - x_0\right)\\
y_1 & = & x_0 + \text{value}\times\left(x_1 - x_0\right)
\end{eqnarray}
is_swappable = 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 a SymmetricTwoportAdaptor operation."""
super().__init__(
input_count=2,
output_count=2,
input_sources=[src0, src1],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
@classmethod
def type_name(cls) -> TypeName:
def evaluate(self, a, b):
return b + tmp, a + tmp
@property
"""Get the constant value of this operation."""
return self.param("value")
@value.setter
"""Set the constant value of this operation."""
if -1 <= value <= 1:
self.set_param("value", value)
else:
raise ValueError('value must be between -1 and 1 (inclusive)')
def swap_io(self) -> None:
# Swap inputs and outputs and change sign of coefficient
self._input_ports.reverse()
for i, p in enumerate(self._input_ports):
p._index = i
self._output_ports.reverse()
for i, p in enumerate(self._output_ports):
p._index = i
self.set_param("value", -self.value)
class Reciprocal(AbstractOperation):
r"""
Reciprocal operation.
Gives the reciprocal of its input.
.. math:: y = \frac{1}{x}
Parameters
----------
src0 : :class:`~b_asic.port.SignalSourceProvider`, optional
The signal to compute the reciprocal 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).
See also
========
Division
"""
def __init__(
self,
src0: Optional[SignalSourceProvider] = None,
name: Name = Name(""),
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
):
"""Construct a Reciprocal operation."""
super().__init__(
input_count=1,
output_count=1,
name=Name(name),
input_sources=[src0],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
)
@classmethod
def type_name(cls) -> TypeName:
return TypeName("rec")
def evaluate(self, a):
return 1 / a
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
class RightShift(AbstractOperation):
r"""
Arithmetic right-shift operation.
Shifts the input to the right assuming a fixed-point representation, so
a multiplication by a power of two.
.. math:: y = x \gg \text{value} = 2^{-\text{value}}x \text{ where value} \geq 0
Parameters
----------
value : int
Number of bits to shift right.
src0 : :class:`~b_asic.port.SignalSourceProvider`, optional
The signal to shift right.
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
--------
LeftShift
Shift
"""
is_linear = True
def __init__(
self,
value: int = 0,
src0: Optional[SignalSourceProvider] = None,
name: Name = Name(""),
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
):
"""Construct a RightShift operation with the given value."""
super().__init__(
input_count=1,
output_count=1,
name=Name(name),
input_sources=[src0],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
)
self.value = value
@classmethod
def type_name(cls) -> TypeName:
return TypeName("rshift")
def evaluate(self, a):
return a * 2 ** (-self.param("value"))
@property
def value(self) -> int:
"""Get the constant value of this operation."""
return self.param("value")
@value.setter
def value(self, value: int) -> None:
"""Set the constant value of this operation."""
if not isinstance(value, int):
raise TypeError("value must be an int")
if value < 0:
raise ValueError("value must be non-negative")
self.set_param("value", value)
class LeftShift(AbstractOperation):
r"""
Arithmetic left-shift operation.
Shifts the input to the left assuming a fixed-point representation, so
a multiplication by a power of two.
.. math:: y = x \ll \text{value} = 2^{\text{value}}x \text{ where value} \geq 0
Parameters
----------
value : int
Number of bits to shift left.
src0 : :class:`~b_asic.port.SignalSourceProvider`, optional
The signal to shift left.
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
--------
RightShift
Shift
"""
is_linear = True
def __init__(
self,
value: int = 0,
src0: Optional[SignalSourceProvider] = None,
name: Name = Name(""),
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
):
"""Construct a RightShift operation with the given value."""
super().__init__(
input_count=1,
output_count=1,
name=Name(name),
input_sources=[src0],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
)
self.value = value
@classmethod
def type_name(cls) -> TypeName:
return TypeName("lshift")
def evaluate(self, a):
return a * 2 ** (self.param("value"))
@property
def value(self) -> int:
"""Get the constant value of this operation."""
return self.param("value")
@value.setter
def value(self, value: int) -> None:
"""Set the constant value of this operation."""
if not isinstance(value, int):
raise TypeError("value must be an int")
if value < 0:
raise ValueError("value must be non-negative")
self.set_param("value", value)
class Shift(AbstractOperation):
r"""
Arithmetic shift operation.
Shifts the input to the left or right assuming a fixed-point representation, so
a multiplication by a power of two. By definition a positive value is a shift to
the left.
.. math:: y = x \ll \text{value} = 2^{\text{value}}x
Parameters
----------
value : int
Number of bits to shift. Positive *value* shifts to the left.
src0 : :class:`~b_asic.port.SignalSourceProvider`, optional
The signal to shift.
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
--------
LeftShift
RightShift
"""
is_linear = True
def __init__(
self,
value: int = 0,
src0: Optional[SignalSourceProvider] = None,
name: Name = Name(""),
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
):
"""Construct a Shift operation with the given value."""
super().__init__(
input_count=1,
output_count=1,
name=Name(name),
input_sources=[src0],
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
)
self.value = value
@classmethod
def type_name(cls) -> TypeName:
return TypeName("shift")
def evaluate(self, a):
return a * 2 ** (self.param("value"))
@property
def value(self) -> int:
"""Get the constant value of this operation."""
return self.param("value")
@value.setter
def value(self, value: int) -> None:
"""Set the constant value of this operation."""
if not isinstance(value, int):
raise TypeError("value must be an int")
self.set_param("value", value)
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
class Sink(AbstractOperation):
r"""
Sink operation.
Used for ignoring the output from another operation to avoid dangling output nodes.
Parameters
==========
name : Name, optional
Operation name.
"""
_execution_time = 0
is_linear = True
def __init__(self, name: Name = ""):
"""Construct a Sink operation."""
super().__init__(
input_count=1,
output_count=0,
name=name,
latency_offsets={"in0": 0},
)
@classmethod
def type_name(cls) -> TypeName:
return TypeName("sink")
def evaluate(self):
raise NotImplementedError
@property
def latency(self) -> int:
return self.latency_offsets["in0"]
def __repr__(self) -> str:
return "Sink()"
def __str__(self) -> str:
return "sink"