b_asic.sfg

B-ASIC Signal Flow Graph Module.

Contains the signal flow graph operation.

class b_asic.sfg.GraphIDGenerator(id_number_offset: GraphIDNumber = 0)

Bases: object

Generates Graph IDs for objects.

property id_number_offset: GraphIDNumber

Get the graph id number offset of this generator.

next_id(type_name: TypeName, used_ids: MutableSet = {}) GraphID

Get the next graph id for a certain graph id type.

class b_asic.sfg.SFG(inputs: Sequence[Input] | None = None, outputs: Sequence[Output] | None = None, input_signals: Sequence[Signal] | None = None, output_signals: Sequence[Signal] | None = None, id_number_offset: GraphIDNumber = 0, name: str = '', input_sources: Sequence[SignalSourceProvider | None] | None = None)

Bases: AbstractOperation

Construct an SFG given its inputs and outputs.

Contains a set of connected operations, forming a new operation. Used as a base for simulation, scheduling, etc.

Inputs/outputs may be specified using either Input/Output operations directly with the inputs/outputs parameters, or using signals with the input_signals/output_signals parameters. If signals are used, the corresponding Input/Output operations will be created automatically.

The id_number_offset parameter specifies what number graph IDs will be offset by for each new graph component type. IDs start at 1 by default, so the default offset of 0 will result in IDs like “c1”, “c2”, etc. while an offset of 3 will result in “c4”, “c5”, etc.

Parameters:
inputsarray of Input, optional
outputsarray of Output, optional
input_signalsarray of Signal, optional
output_signalsarray of Signal, optional
id_number_offsetGraphIDNumber, optional
nameName, optional
input_sources
property components: list[GraphComponent]

Get all components of this graph in depth-first order.

connect_external_signals_to_components() bool

Connect any external signals to the internal operations of SFG.

This SFG becomes unconnected to the SFG it is a component off, causing it to become invalid afterwards. Returns True if successful, False otherwise.

copy(*args, **kwargs) GraphComponent

Get a new instance of this graph component type.

The new instance will have the same name, id, and parameters.

critical_path_time() int

Return the time of the critical path.

edit() dict[str, SFG]

Edit SFG in GUI.

evaluate(*args, data_type=None) int | float | complex | DTypeLike | APyFixed | APyCFixed | APyFloat | APyCFloat | list[int | float | complex | DTypeLike | APyFixed | APyCFixed | APyFloat | APyCFloat] | None

Evaluate the operation and generate a list of output values.

Parameters:
*inputs

List of input values.

data_typeDataType, optional

Data type to use for quantization during evaluation.

evaluate_output(index: int, input_values: Sequence[int | float | complex | DTypeLike | APyFixed | APyCFixed | APyFloat | APyCFloat], results: MutableMapping[ResultKey, int | float | complex | DTypeLike | APyFixed | APyCFixed | APyFloat | APyCFloat | None] | None = None, delays: MutableMapping[ResultKey, int | float | complex | DTypeLike | APyFixed | APyCFixed | APyFloat | APyCFloat] | None = None, prefix: str = '', data_type: DataType | None = None) int | float | complex | DTypeLike | APyFixed | APyCFixed | APyFloat | APyCFloat

Evaluate the output at the given index with the given input values.

Parameters:
indexint

Which output to return the value for.

input_valuesarray of float or complex

The input values.

resultsMutableResultMap, optional

Used to store any results (including intermediate results) for caching.

delaysMutableDelayMap, optional

Used to get the current value of any intermediate delay elements that are encountered, and be updated with their new values.

prefixstr, optional

Used as a prefix for the key string when storing results/delays.

data_typeDataType, optional

Data type to use for quantization during evaluation.

See also

evaluate_outputs, current_output, current_outputs
property expression: str

Get the full (recursively evaluated) expressions defining the SFG.

extract(targets: Iterable[GraphID]) SFG
find_all_paths(graph: dict, start: str, end: str, path: list | None = None) list

Find all paths in graph from node start to node end.

Parameters:
graphdictionary

The dictionary that are to be searched for loops.

startkey in dictionary graph

The “node” in the dictionary that are set as the start point.

endkey in dictionary graph

The “node” in the dictionary that are set as the end point.

pathlist

This parameter should not be provided directly and is only used internally.

Returns:
The state-space representation of the SFG.
find_by_id(graph_id: GraphID) GraphComponent | None

Find the graph component with the specified ID.

Returns None if the component was not found.

Parameters:
graph_idGraphID

Graph ID of the desired component.

find_by_name(name: str) Sequence[GraphComponent]

Find all graph components with the specified name.

Returns an empty sequence if no components were found.

Parameters:
nameName

Name of the desired component(s).

find_by_type(component_type: type[GraphComponent]) list[GraphComponent]

Find all components in this graph with the specified type.

Returns an empty list if no components were found.

Parameters:
component_typetype of GraphComponent

The TypeName of the desired components.

find_by_type_name(type_name: TypeName) list[GraphComponent]

Find all components in this graph with the specified type name.

Returns an empty list if no components were found.

Parameters:
type_nameTypeName

The TypeName of the desired components.

find_result_keys_by_name(name: str, output_index: int = 0) Sequence[ResultKey]

Find all graph components with the specified name.

Return a sequence of the keys to use when fetching their results from a simulation.

Parameters:
nameName

Name of the desired component(s).

output_indexint, default: 0

The desired output index to get the result from.

flatten(expand: bool = False) SFG

Return a new SFG with all sub-SFG operations recursively inlined.

Any operation in this SFG that is itself an SFG will have its internal operations merged into the returned SFG. This is applied recursively until no nested SFGs remain.

Parameters:
expandbool, optional

If True, also expand composite operations (e.g. SymmetricTwoportAdaptor) into their primitive sub-operations via their to_sfg() method. Operations whose to_sfg() only wraps themselves (i.e. primitives) are left unchanged.

get_impulse_responses(threshold: float = 1e-12, max_iters: int = -1, all_nodes: bool = False) dict[str, list[ndarray[tuple[Any, ...], dtype[_ScalarT]]]]

Return the impulse response for all output ports of all operations in the SFG.

The simulation runs until all output and delay values decay below the threshold. One impulse response is computed for each SFG input.

Parameters:
thresholdfloat, default: 1e-12

The threshold below which output values are considered to have decayed to zero.

all_nodesbool, default: False

If True, impulse responses are collected for all operations. If False, only output operations of the SFG are collected.

max_itersint, default: -1

Maximum number of simulation time steps to prevent infinite loops. If -1, there is no limit.

Returns:
dict[str, list[npt.NDArray]]

Dictionary mapping each operation’s output port key (e.g., “add1.0”, “mul2.0”) to a list of impulse responses (as numpy arrays), one for each SFG input.

get_impulse_responses_from_nodes(nodes: list[GraphID] | None = None, threshold: float = 1e-12, max_iters: int = -1) dict[str, dict[str, ndarray[tuple[Any, ...], dtype[_ScalarT]]]]

Return the impulse responses for the specified nodes to the SFG outputs.

Can e.g. be used to compute roundoff noise gains.

The simulation runs until all output and delay values decay below the threshold. Alternatively, a maximum number of iterations can be set to prevent infinite loops.

Parameters:
nodeslist[GraphID], optional

List of operation GraphIDs where impulses should be injected.

thresholdfloat, default: 1e-12

The threshold below which output values are considered to have decayed to zero.

max_itersint, default: -1

Maximum number of simulation time steps to prevent infinite loops. If -1, there is no limit.

Returns:
dict[str, dict[str, npt.NDArray]]

Dictionary mapping each SFG output GraphID (e.g., “out0”, “out1”) to a dictionary that maps operation GraphIDs to their corresponding impulse responses.

get_l1_norms(threshold: float = 1e-12, max_iters: int = -1, all_nodes: bool = False) dict[str, float]
get_operations_topological_order() Iterable[Operation]

Return an Iterable of the Operations in the SFG in topological order.

Feedback loops makes an absolutely correct topological order impossible, so an approximate topological Order is returned in such cases in this implementation.

get_precedence_list() Sequence[Sequence[OutputPort]]

Return a precedence list of the SFG.

In the precedence list each element in n:th the list consists of elements that are executed in the n:th step. If the precedence list already has been calculated for the current SFG then return the cached version.

get_used_graph_ids() set[GraphID]

Get a list of all GraphID:s used in the SFG.

get_used_operation_types() list[type[Operation]]

Get a list of all Operations used in the SFG.

get_used_type_names() list[TypeName]

Get a list of all TypeNames used in the SFG.

property id_number_offset: GraphIDNumber

Get the graph id number offset of the graph id generator for this SFG.

property input_operations: Sequence[Operation]

Internal input operations in the same order as their respective input ports.

inputs_required_for_output(output_index: int) Iterable[int]

Return which inputs that the output depends on.

Parameters:
output_indexint

The output index.

Returns:
A list of inputs that are required to compute the output with the given
output_index.
insert_operation(component: Operation, output_comp_id: GraphID, port: int | None = None) SFG

Insert an operation in the SFG after a given source operation.

The source operation output count must match the input count of the operation as well as the output. Then return a new deepcopy of the sfg with the inserted component.

Parameters:
componentOperation

The new component, e.g. Multiplication.

output_comp_idGraphID

The source operation GraphID to connect from. Can use 'id.port' notation to specify a port, e.g. 'sym2p4.1'.

portint, optional

The number of the OutputPort after which the new operation shall be inserted. Overridden by dot notation in output_comp_id.

insert_operation_after(output_comp_id: GraphID, new_operation: Operation, port: int | None = None) SFG

Insert an operation in the SFG after a given source operation.

Then return a new deepcopy of the sfg with the inserted component.

The graph_id can be an Operation or a Signal. If the operation has multiple outputs, (copies of) the new operation will be inserted on every port. To specify a port use 'graph_id.port_number', e.g., 'sym2p4.1', or the port parameter.

Parameters:
output_comp_idGraphID

The source operation GraphID to connect from. Can use 'id.port' notation to specify a port, e.g. 'sym2p4.1'.

new_operationOperation

The new operation, e.g. Multiplication.

portint, optional

The number of the OutputPort after which the new operation shall be inserted. Overridden by dot notation in output_comp_id.

insert_operation_before(input_comp_id: GraphID, new_operation: Operation, port: int | None = None) SFG

Insert an operation in the SFG before a given source operation.

Then return a new deepcopy of the sfg with the inserted component.

The graph_id can be an Operation or a Signal. If the operation has multiple inputs, (copies of) the new operation will be inserted on every port. To specify a port use 'graph_id.port_number', e.g., 'sym2p4.1', or the port parameter.

Parameters:
input_comp_idGraphID

The source operation GraphID to connect to. Can use 'id.port' notation to specify a port, e.g. 'sym2p4.0'.

new_operationOperation

The new operation, e.g. Multiplication.

portint, optional

The number of the InputPort before which the new operation shall be inserted. Overridden by dot notation in input_comp_id.

property is_constant: bool

Return True if the output(s) of the operation is(are) constant.

property is_linear: bool

Return True if the operation is linear.

iteration_period_bound() Fraction

Return the iteration period bound of the SFG.

If -1, the SFG does not have any loops and therefore no iteration period bound.

Returns:
The iteration period bound.
join(target: GraphID, direction: Literal['forward', 'backward']) SFG

Return a new SFG with the specified operation joined with its predecessor or successor.

Parameters:
targetGraphID

The operation to be joined with its predecessor(s) or successor(s).

direction{“forward”, “backward”}

The direction to join. “forward” joins with the successor(s), “backward” with the predecessor(s).

property loops: list[list[GraphID]]

Return the recursive loops found in the SFG.

Returns:
A list of the recursive loops.
operation_counter() Counter

Return a Counter with the number of instances for each type.

property operations: list[Operation]

Get all operations of this graph in depth-first order.

property output_operations: Sequence[Operation]

Internal output operations in the same order as their respective output ports.

property precedence_graph: Digraph

The SFG in precedence form in Graphviz format.

This can be rendered in enriched shells.

print_precedence_graph() None

Print a representation of the SFG precedence list to the standard out.

If the precedence list already has been calculated then it uses the cached version, otherwise it calculates the precedence list and then prints it.

remove_operation(operation_id: GraphID) SFG | None

Remove operation.

Returns a version of the SFG where the operation with the specified GraphID removed.

The operation must have the same amount of input- and output ports or a ValueError is raised. If no operation with the entered operation_id is found then returns None and does nothing.

Parameters:
operation_idGraphID

The GraphID of the operation to remove.

replace(target: GraphID, component: Operation) SFG
resource_lower_bound(type_name: TypeName, schedule_time: int) int

Return the lowest amount of resources of the given type needed to reach the scheduling time.

Parameters:
type_nameTypeName

Type name of the given resource.

schedule_timeint

Scheduling time to evaluate for.

rewrite(source: type[Operation], target: GraphID | type[Operation] | Operation | Iterable[GraphID | type[Operation] | Operation]) None

Return a new SFG with the specified operations rewritten.

The operations specified by target are replaced by the operations specified by substitute.

Parameters:
sourceType[Operation]

The type of operation to replace the target(s) with.

targetOpSpecifier | Iterable[OpSpecifier]

The operation(s) to be replaced.

set_execution_time_of_type(operation_type: type[Operation], execution_time: int) None

Set the latency of all operations with the given type.

Parameters:
operation_typetype of Operation

The operation type. For example, Addition.

execution_timeint

The execution time of the operation.

set_execution_time_of_type_name(type_name: TypeName, execution_time: int) None

Set the execution time of all operations with the given type name.

Parameters:
type_nameTypeName

The type name of the operation. For example, obtained as Addition.type_name().

execution_timeint

The execution time of the operation.

set_latency_of_type(operation_type: type[Operation], latency: int) None

Set the latency of all operations with the given type.

Parameters:
operation_typetype of Operation

The operation type. For example, Addition.

latencyint

The latency of the operation.

set_latency_of_type_name(type_name: TypeName, latency: int) None

Set the latency of all components with the given type name.

Parameters:
type_nameTypeName

The type name of the operation. For example, obtained as Addition.type_name().

latencyint

The latency of the operation.

set_latency_offsets_of_type(operation_type: type[Operation], latency_offsets: dict[str, int]) None

Set the latency offsets of all operations with the given type.

Parameters:
operation_typetype of Operation

The operation type. For example, Addition.

latency_offsets{“in1”: int, …}

The latency offsets of the inputs and outputs.

set_latency_offsets_of_type_name(type_name: TypeName, latency_offsets: dict[str, int]) None

Set the latency offsets of all operations with the given type name.

Parameters:
type_nameTypeName

The type name of the operation. For example, obtained as Addition.type_name().

latency_offsets{“in1”: int, …}

The latency offsets of the inputs and outputs.

sfg_digraph(signal_info: Literal['none', 'id', 'l1-norm'] = 'none', engine: str | None = None, branch_node: bool = True, port_numbering: bool = True, splines: Literal['spline', 'line', 'ortho', 'polyline', 'curved'] = 'spline', input_order: list[GraphID] | None = None, output_order: list[GraphID] | None = None, show_op_params: bool = False, direction: Literal['LR', 'TB'] = 'LR', ranksep: float | None = None, nodesep: float | None = None, size: tuple[float, float] | None = None, force_size: bool = False, fontname: str | None = None, fontsize: float | None = None) Digraph

Return a Digraph of the SFG.

Can be directly displayed in IPython.

Parameters:
signal_info{“none”, “id”, “l1-norm”}, default: “none”
Information to show for each signal in the graph.
  • “none”: Do not show any signal information.

  • “id”: Show the graph_id of each signal.

  • “l1-norm”: Show the L1 norm of the impulse response (worst-case magnitude for inputs in [-1, 1]).

enginestr, optional

Graphviz layout engine to be used, see https://graphviz.org/documentation/. Most common are “dot” and “neato”. Default is None leading to dot.

branch_nodebool, default: True

Add a branch node in case the fan-out of a signal is two or more.

port_numberingbool, default: True

Show the port number in case the number of ports (input or output) is two or more.

splines{“spline”, “line”, “ortho”, “polyline”, “curved”}, default: “spline”

Spline style, see https://graphviz.org/docs/attrs/splines/ for more info.

input_orderlist of GraphID or operation name, optional

Top-to-bottom ordering of input nodes. Defaults to the SFG’s natural input order.

output_orderlist of GraphID or operation name, optional

Top-to-bottom ordering of output nodes. Defaults to the SFG’s natural output order.

show_op_paramsbool, default: False

Annotate each operation node with its non-default-valued parameters.

direction{“LR”, “TB”}, default: “LR”
Direction of the graph layout.
  • “LR”: Left-to-right (inputs on the left, outputs on the right).

  • “TB”: Top-to-bottom (inputs at the top, outputs at the bottom).

ranksepfloat, optional

Separation between ranks in inches. Default is graphviz’s default (0.5).

nodesepfloat, optional

Minimum separation between nodes in the same rank, in inches. Default is graphviz’s default (0.25).

sizetuple of (float, float), optional

Maximum bounding box of the drawing as (width, height) in inches, e.g. (10, 5).

force_sizebool, default: False

When True, the size bounding box is treated as an exact target and graphviz scales the entire drawing (including fonts) to fill it.

fontnamestr, optional

Font name for all node and edge labels, e.g. "Times New Roman".

fontsizefloat, optional

Font size (in points) for all node and edge labels. Note: if force_size=True, graphviz will scale fonts along with the rest of the drawing to meet the exact size target.

show(fmt: str | None = None, signal_info: Literal['none', 'id', 'l1-norm'] = 'none', engine: str | None = None, branch_node: bool = True, port_numbering: bool = True, splines: Literal['spline', 'line', 'ortho', 'polyline', 'curved'] = 'spline', input_order: list[GraphID] | None = None, output_order: list[GraphID] | None = None, show_op_params: bool = False, direction: Literal['LR', 'TB'] = 'LR', ranksep: float | None = None, nodesep: float | None = None, size: tuple[float, float] | None = None, force_size: bool = False, fontname: str | None = 'Times New Roman', fontsize: float | None = None) None

Display a visual representation of the SFG using the default system viewer.

Parameters:
fmtstr, optional

File format of the generated graph. Output formats can be found at https://www.graphviz.org/doc/info/output.html Most common are “pdf”, “eps”, “png”, and “svg”. Default is None which leads to PDF.

enginestr, optional

Graphviz layout engine to be used, see https://graphviz.org/documentation/. Most common are “dot” and “neato”. Default is None leading to dot.

branch_nodebool, default: True

Add a branch node in case the fan-out of a signal is two or more.

port_numberingbool, default: True

Show the port number in case the number of ports (input or output) is two or more.

splines{“spline”, “line”, “ortho”, “polyline”, “curved”}, default: “spline”

Spline style, see https://graphviz.org/docs/attrs/splines/ for more info.

signal_info{“none”, “id”, “l1-norm”}, default: “none”
Information to show for each signal in the graph.
  • “none”: Do not show any signal information.

  • “id”: Show the graph_id of each signal.

  • “l1-norm”: Show the L1 norm of the impulse response (worst-case magnitude for inputs bounded by 1).

input_orderlist of GraphID or operation name, optional

Top-to-bottom ordering of input nodes. Each entry may be a GraphID, an operation name, or a mix of both. See sfg_digraph() for details.

output_orderlist of GraphID or operation name, optional

Top-to-bottom ordering of output nodes. Each entry may be a GraphID, an operation name, or a mix of both. See sfg_digraph() for details.

show_op_paramsbool, default: False

Annotate each operation node with its non-default-valued parameters.

direction{“LR”, “TB”}, default: “LR”
Direction of the graph layout.
  • “LR”: Left-to-right (inputs on the left, outputs on the right).

  • “TB”: Top-to-bottom (inputs at the top, outputs at the bottom).

ranksepfloat, optional

Separation between ranks in inches. Default is graphviz’s default (0.5).

nodesepfloat, optional

Minimum separation between nodes in the same rank, in inches. Default is graphviz’s default (0.25).

sizetuple of (float, float), optional

Maximum bounding box in inches of the drawing as (width, height).

force_sizebool, default: False

When True, the size bounding box is treated as an exact target and graphviz scales the entire drawing (including fonts) to fill it.

fontnamestr, default: “Times New Roman”

Font name for all node and edge labels.

fontsizefloat, optional

Font size (in points) for all node and edge labels.

show_precedence_graph() None

Display the output of precedence_graph() in the system viewer.

simplify_delay_element_placement() SFG

Simplify an SFG by removing redundant delay elements.

For example, two signals originating from the same starting point, each connected to a delay element will combine into a single delay element.

Returns a copy of the simplified SFG.

split() Iterable[Operation]

Split the operation into multiple operations.

If splitting is not possible, this may return a list containing only the operation itself.

swap_io_of_operation(operation_id: GraphID) None

Swap the inputs (and outputs) of operation.

Parameters:
operation_idGraphID

The GraphID of the operation to swap.

to_sfg() SFG

Convert the operation into its corresponding SFG.

If the operation is composed by multiple operations, the operation will be split.

to_ss() StateSpace

Return the state-space representation of the SFG.

Returns:
The state-space representation.
to_tf()

Return the transfer function representation of the SFG.

Returns:
The transfer function representation.
to_zpk()

Return the zeros, poles, and gain of the SFG.

Returns:
dict

See zpk() for the return format.

classmethod type_name() TypeName

Get the type name of this graph component.

unfold(factor: int) SFG

Unfold the SFG factor times. Return a new SFG without modifying the original.

Inputs and outputs are ordered with early inputs first. That is for an SFG with n inputs, the first n inputs are the inputs at time t, the next n inputs are the inputs at time t+1, the next n at t+2 and so on.

Parameters:
factorint

Number of times to unfold.