piel.integration#

Submodules#

Attributes#

Functions#

create_cocotb_truth_table_verification_python_script(...)

Creates a cocotb test script for verifying logic defined by the truth table.

layout_amaranth_truth_table_through_openlane(...[, ...])

Implements an Amaranth truth table module through the OpenLane flow.

layout_truth_table_through_openlane(truth_table, ...)

Translates a truth table to an OpenLane flow implementation.

create_gdsfactory_component_from_openlane(...)

gdsfactory_netlist_to_spice_string_connectivity_netlist(...)

Not for the hdl21 design flow, but useful for other SPICE level conversions.

gdsfactory_netlist_to_spice_netlist(...)

This function converts a GDSFactory electrical netlist into a standard SPICE netlist. It follows the same

gdsfactory_netlist_with_hdl21_generators(...[, generators])

This function allows us to map the hdl21 measurement dictionary in a sax-like implementation to the GDSFactory netlist. This allows us to iterate over each instance in the netlist and construct a circuit after this function.]

get_matching_connections(names, connections)

This function returns a list of tuples that match the names of the connections.

get_matching_port_nets(names, connections)

construct_hdl21_module(→ piel.types.AnalogueModule)

This function converts a gdsfactory-spice converted netlist using the component measurement into a SPICE circuit.

convert_connections_to_tuples(connections)

Convert from:

filter_port(port)

Filter the port name to match spice declaration to gds port name, specifically focused on the SKY130nm technology.

find_most_relevant_gds(component_name[, ...])

hdl21_module_to_schematic_editor(module, ...[, ...])

Constructs a SchematicEditor instance from a hdl21 module object.

generate_raw_yaml_from_module(module)

Generate a raw netlist yaml from a hdl21 module object which could be manually edited for specific instances

generate_raw_netlist_dict_from_module(module)

Generate a raw netlist dictionary from a hdl21 module object.

sax_circuit_permanent(→ tuple)

The permanent of a unitary is used to determine the state probability of combinatorial Gaussian boson samping systems.

sax_to_s_parameters_standard_matrix(...)

A sax S-parameter SDict is provided as a dictionary of tuples with (port0, port1) as the key. This

sax_to_ideal_qutip_unitary(sax_input[, input_ports_order])

verify_sax_model_is_unitary(→ bool)

fock_transition_probability_amplitude(...)

This function returns the transition probability amplitude between two Fock states when propagating in between

convert_to_network_transmission(...)

This function takes in any supported FrequencyTransmissionModel and provides translation between the different

Package Contents#

create_cocotb_truth_table_verification_python_script(module: piel.types.PathTypes, truth_table: piel.types.digital.TruthTable, test_python_module_name: str = 'top_test')[source]#

Creates a cocotb test script for verifying logic defined by the truth table.

Parameters:
  • module (PathTypes) – The path to the module where the test script will be placed.

  • truth_table (TruthTable) – A dictionary representing the truth table.

  • test_python_module_name (str, optional) – The name of the test python module. Defaults to “top_test”.

Example

truth_table = {

“A”: [0, 0, 1, 1], “B”: [0, 1, 0, 1], “X”: [0, 1, 1, 0] # Expected output (for XOR logic, as an example)

} create_cocotb_truth_table_verification_python_script(truth_table)

layout_amaranth_truth_table_through_openlane(amaranth_module: piel.types.DigitalLogicModule, truth_table: piel.types.TruthTable, parent_directory: piel.types.PathTypes, target_directory_name: str | None = None, openlane_version: Literal['v1', 'v2'] = 'v2', openlane_configuration: dict | None = None, **kwargs)[source]#

Implements an Amaranth truth table module through the OpenLane flow.

This function implements an amaranth truth-table module through the openlane flow. There are several ways to implement a module. Fundamentally, this requires the verilog files to be generated from the openlane-module in a particular directory. For the particular directory provided, this function will generate the verilog files in the corresponding directory. It can also generate the openlane configuration files for this particular location.

This function does a few things:

  1. Starts off from a amaranth module class.

  2. Determines the output directory in which to generate the files, and creates one accordingly if it does not exist.

  3. Generates the verilog files from the amaranth module class.

  4. Generates the openlane configuration files for this particular location.

  5. Implements the openlane flow for this particular location to generate a chip.

Parameters:
  • amaranth_module (am.Module) – The Amaranth module representing the truth table logic.

  • truth_table (TruthTable) – The truth table files structure containing the logic for the module.

  • parent_directory (PathTypes) – The directory where the project will be created or found.

  • target_directory_name (Optional[str]) – The name for the target directory. Defaults to the name of the Amaranth module’s class.

  • openlane_version (Literal["v1", "v2"]) – The version of OpenLane to use. Defaults to “v2”.

  • **kwargs – Additional keyword arguments for OpenLane configuration.

Returns:

None

layout_truth_table_through_openlane(truth_table: piel.types.TruthTable, parent_directory: piel.types.PathTypes, target_directory_name: str | None = None, openlane_version: Literal['v1', 'v2'] = 'v2', **kwargs)[source]#

Translates a truth table to an OpenLane flow implementation.

This function takes a truth table and converts it into an OpenLane flow, using the specified OpenLane version. It first constructs an Amaranth module from the truth table, and then passes this module to the layout_amaranth_truth_table_through_openlane function for further processing.

Parameters:
  • truth_table (TruthTable) – The truth table to be converted. It includes input connection, output connection, and the table logic.

  • parent_directory (PathTypes) – The directory where the OpenLane project will be created.

  • target_directory_name (Optional[str]) – Name of the target directory. If not specified, a default name will be used.

  • openlane_version (Literal["v1", "v2"]) – Specifies the OpenLane version to use. Defaults to “v2”.

  • **kwargs – Additional keyword arguments passed to the Amaranth module construction.

Returns:

None

create_gdsfactory_component_from_openlane(design_name_v1: str | None = None, design_directory: piel.types.PathTypes | None = None, run_name: str | None = None, v1: bool = False) piel.types.PhotonicCircuitComponent[source]#
gdsfactory_netlist_to_spice_string_connectivity_netlist(gdsfactory_netlist: dict, models=None)[source]#

Not for the hdl21 design flow, but useful for other SPICE level conversions.

This function maps the connections of a netlist to a node that can be used in a SPICE netlist. SPICE netlists are in the form of:

RXXXXXXX N1 N2 <VALUE> <MNAME> <L=LENGTH> <W=WIDTH> <TEMP=T>

This means that every instance, is an electrical type, and we define the two particular nodes in which it is connected. This means we need to convert the gdsfactory dictionary netlist into a form that allows us to map the connectivity for every instance. Then we can define that as a line of the SPICE netlist with a particular electrical model. For passives this works fine when it’s a two port network such as sources, or electrical elements. However, non-passive elements like transistors have three connection or more which are provided in an ordered form.

This means that the order of translations is as follows:

1. Extract all instances and required measurement from the netlist, and assign the corresponding parameters on instantiation.
2. Verify that the measurement have been provided. Each model describes the type of component this is, how many connection it requires and so on.
3. Map the connections to each instance port as part of the instance dictionary.

We should get as an output a dictionary in the structure:

{
    instance_1: {
        ...
        "connections": [('straight_1,e1', 'taper_1,e2'),
                        ('straight_1,e2', 'taper_2,e2')],
        'spice_nets': {'e1': 'straight_1__e1___taper_1__e2',
                'e2': 'straight_1__e2___taper_2__e2'},
        'spice_model': <function piel.measurement.physical.electronic.spice.resistor.basic_resistor()>},
    }
    ...
}
gdsfactory_netlist_to_spice_netlist(gdsfactory_netlist: dict, generators: dict, **kwargs) piel.types.AnalogueModule[source]#

This function converts a GDSFactory electrical netlist into a standard SPICE netlist. It follows the same principle as the sax circuit composition.

Each GDSFactory netlist has a set of instances, each with a corresponding model, and each instance with a given set of geometrical settings that can be applied to each particular model. We know the type of SPICE model from the instance model we provides.

We know that the gdsfactory has a set of instances, and we can map unique measurement via sax through our own composition circuit. Write the SPICE component based on the model into a total circuit representation in string from the reshaped gdsfactory dictionary into our own structure.

Parameters:
  • gdsfactory_netlist – GDSFactory netlist

  • generators – Dictionary of Generators

Returns:

hdl21 module or raw SPICE string

gdsfactory_netlist_with_hdl21_generators(gdsfactory_netlist: dict, generators=None)[source]#

This function allows us to map the hdl21 measurement dictionary in a sax-like implementation to the GDSFactory netlist. This allows us to iterate over each instance in the netlist and construct a circuit after this function.]

Example usage:

>>> import gdsfactory as gf
>>> from piel.integration.gdsfactory_hdl21.conversion import gdsfactory_netlist_with_hdl21_generators
>>> from piel.measurement.physical.electronic import get_default_models
>>> gdsfactory_netlist_with_hdl21_generators(gdsfactory_netlist=gf.components.mzi2x2_2x2_phase_shifter().get_netlist(exclude_port_types="optical"),generators=get_default_models())
Parameters:
  • gdsfactory_netlist – The netlist from GDSFactory to map to the hdl21 measurement dictionary.

  • generators – The hdl21 measurement dictionary to map to the GDSFactory netlist.

Returns:

The GDSFactory netlist with the hdl21 measurement dictionary.

get_matching_connections(names: list, connections: dict)[source]#

This function returns a list of tuples that match the names of the connections.

Parameters:
  • names – List of names to match

  • connections – Dictionary of connections to match

Returns:

List of tuples that match the names of the connections

get_matching_port_nets(names, connections)[source]#
construct_hdl21_module(spice_netlist: dict, **kwargs) piel.types.AnalogueModule[source]#

This function converts a gdsfactory-spice converted netlist using the component measurement into a SPICE circuit.

Part of the complexity of this function is the multiport nature of some components and measurement, and assigning the parameters accordingly into the SPICE function. This is because not every SPICE component will be bi-port, and many will have multi-connection and parameters accordingly. Each model can implement the composition into a SPICE circuit, but they depend on a set of parameters that must be set from the instance. Another aspect is that we may want to assign the component ID according to the type of component. However, we can also assign the ID based on the individual instance in the circuit, which is also a reasonable approximation. However, it could be said, that the ideal implementation would be for each component model provided to return the SPICE instance including connectivity except for the ID.

# TODO implement validators

convert_connections_to_tuples(connections: dict)[source]#

Convert from:

{
'straight_1,e1': 'taper_1,e2',
'straight_1,e2': 'taper_2,e2',
'taper_1,e1': 'via_stack_1,e3',
'taper_2,e1': 'via_stack_2,e1'
}

to:

[(('straight_1', 'e1'), ('taper_1', 'e2')), (('straight_1', 'e2'), ('taper_2', 'e2')), (('taper_1', 'e1'),
('via_stack_1', 'e3')), (('taper_2', 'e1'), ('via_stack_2', 'e1'))]
filter_port(port)[source]#

Filter the port name to match spice declaration to gds port name, specifically focused on the SKY130nm technology.

find_most_relevant_gds(component_name, component_dict=None, custom_mapping=None)[source]#
hdl21_module_to_schematic_editor(module: piel.types.AnalogueModule, yaml_schematic_file_name: str, spice_gds_mapping_method: Callable | None = find_most_relevant_gds, port_filter_method: Callable = filter_port)[source]#

Constructs a SchematicEditor instance from a hdl21 module object.

Parameters:
  • module (h.module) – The hdl21 module object.

  • yaml_schematic_file_name (str) – The yaml schematic file name.

  • spice_gds_mapping_method (Callable) – The method to map the spice instance name to the component name.

  • port_filter_method (Callable) – The method to filter the port name.

generate_raw_yaml_from_module(module: piel.types.AnalogueModule)[source]#

Generate a raw netlist yaml from a hdl21 module object which could be manually edited for specific instances related to the corresponding SPICE.

generate_raw_netlist_dict_from_module(module: piel.types.AnalogueModule)[source]#

Generate a raw netlist dictionary from a hdl21 module object. This just gives us a raw structure of the hdl21 modules, we cannot use this json equivalently to a gdsfactory netlist.

ParsedProtoVLSIR#
sax_circuit_permanent(sax_input: Any) tuple[source]#

The permanent of a unitary is used to determine the state probability of combinatorial Gaussian boson samping systems.

thewalrus Ryser’s algorithm permananet implementation is described here: https://the-walrus.readthedocs.io/en/latest/gallery/permanent_tutorial.html

# TODO maybe implement subroutine if computation is taking forever.

Parameters:

sax_input (sax.SType) – The sax S-parameter dictionary.

Returns:

The circuit permanent and the time it took to compute it.

Return type:

tuple

sax_to_s_parameters_standard_matrix(sax_input: Any, input_ports_order: tuple[str] | None = None, round_int: bool | None = None, *args, **kwargs) piel.types.SParameterMatrixTuple[source]#

A sax S-parameter SDict is provided as a dictionary of tuples with (port0, port1) as the key. This determines the direction of the scattering relationship. It means that the number of terms in an S-parameter matrix is the number of connection squared.

In order to generalise, this function returns both the S-parameter matrices and the indexing connection based on the amount provided. In terms of computational speed, we definitely would like this function to be algorithmically very fast. For now, I will write a simple python implementation and optimise in the future.

It is possible to see the sax SDense notation equivalence here: https://flaport.github.io/sax/nbs/08_backends.html

import jax.numpy as jnp
from sax.core import SDense

# Directional coupler SDense representation
dc_sdense: SDense = (
    jnp.array([[0, 0, τ, κ], [0, 0, κ, τ], [τ, κ, 0, 0], [κ, τ, 0, 0]]),
    {"in0": 0, "in1": 1, "out0": 2, "out1": 3},
)


# Directional coupler SDict representation
# Taken from https://flaport.github.io/sax/nbs/05_models.html
def coupler(*, coupling: float = 0.5) -> SDict:
    kappa = coupling**0.5
    tau = (1 - coupling) ** 0.5
    sdict = reciprocal(
        {
            ("in0", "out0"): tau,
            ("in0", "out1"): 1j * kappa,
            ("in1", "out0"): 1j * kappa,
            ("in1", "out1"): tau,
        }
    )
    return sdict

If we were to relate the mapping accordingly based on the connection indexes, a S-Parameter matrix in the form of \(S_{(output,i),(input,i)}\) would be:

\[\begin{split}S = \begin{bmatrix} S_{00} & S_{10} \\ S_{01} & S_{11} \\ \end{bmatrix} = \begin{bmatrix} \tau & j \kappa \\ j \kappa & \tau \\ \end{bmatrix}\end{split}\]

Note that the standard S-parameter and hence unitary representation is in the form of:

\[\begin{split}S = \begin{bmatrix} S_{00} & S_{01} \\ S_{10} & S_{11} \\ \end{bmatrix}\end{split}\]
\[\begin{split}\begin{bmatrix} b_{1} \\ \vdots \\ b_{n} \end{bmatrix} = \begin{bmatrix} S_{11} & \dots & S_{1n} \\ \vdots & \ddots & \vdots \\ S_{n1} & \dots & S_{nn} \end{bmatrix} \begin{bmatrix} a_{1} \\ \vdots \\ a_{n} \end{bmatrix}\end{split}\]

TODO check with Floris, does this mean we need to transpose the matrix? TODO document round_int

Parameters:
  • sax_input (sax.SType) – The sax S-parameter dictionary.

  • input_ports_order (tuple) – The connection order tuple containing the names and order of the input connection.

  • round_int (bool) – Whether to round the complex numbers to integers.

Returns:

The S-parameter matrix and the input connection index tuple in the standard S-parameter notation.

Return type:

tuple

sax_to_ideal_qutip_unitary(sax_input: piel.types.OpticalTransmissionCircuit, input_ports_order: tuple | None = None)[source]#
verify_sax_model_is_unitary(model: piel.types.OpticalTransmissionCircuit, input_ports_order: tuple | None = None) bool[source]#
fock_transition_probability_amplitude(initial_fock_state: Any, final_fock_state: Any, unitary_matrix: jax.numpy.ndarray)[source]#

This function returns the transition probability amplitude between two Fock states when propagating in between the unitary_matrix which represents a quantum state circuit.

Note that based on (TODO cite Jeremy), the initial Fock state corresponds to the columns of the unitary and the final Fock states corresponds to the rows of the unitary.

\[\]

ewcommand{ket}[1]{left|{#1} ight angle}

The subunitary \(U_{f_1}^{f_2}\) is composed from the larger unitary by selecting the rows from the output state Fock state occupation of \(\ket{f_2}\), and columns from the input \(\ket{f_1}\). In our case, we need to select the columns indexes \((0,3)\) and rows indexes \((1,2)\).

If we consider a photon number of more than one for the transition Fock states, then the Permanent needs to be normalised. The probability amplitude for the transition is described as:

\[a(\ket{f_1} o \ket{f_2}) =\]

rac{ ext{per}(U_{f_1}^{f_2})}{sqrt{(j_1! j_2! … j_N!)(j_1^{‘}! j_2^{‘}! … j_N^{‘}!)}}

Args:

initial_fock_state (qutip.Qobj | jnp.ndarray): The initial Fock state. final_fock_state (qutip.Qobj | jnp.ndarray): The final Fock state. unitary_matrix (jnp.ndarray): The unitary matrix that represents the quantum state circuit.

Returns:

float: The transition probability amplitude between the initial and final Fock states.

convert_to_network_transmission(network: piel.types.FrequencyTransmissionModel) piel.types.NetworkTransmission[source]#

This function takes in any supported FrequencyTransmissionModel and provides translation between the different domain representations and returns a standard NetworkTransmission class.