Skip to content

Shared

inspeqtor.models.shared

inspeqtor.models.shared.mse

mse(x1: ndarray, x2: ndarray)
Source code in src/inspeqtor/v1/model.py
39
40
def mse(x1: jnp.ndarray, x2: jnp.ndarray):
    return jnp.mean((x1 - x2) ** 2)

inspeqtor.models.shared.hermitian

hermitian(U: ndarray, D: ndarray) -> ndarray

This is a function that parametrized Hermitian matrix

Parameters:

Name Type Description Default
U ndarray

Parameters for unitary operator with shape of (..., 3)

required
D ndarray

Parameters for diagonal matrix with shape if (..., 2)

required

Returns:

Type Description
ndarray

jnp.ndarray: Hermitian matrix of shape (..., 2, 2)

Source code in src/inspeqtor/v1/model.py
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
def hermitian(U: jnp.ndarray, D: jnp.ndarray) -> jnp.ndarray:
    """This is a function that parametrized Hermitian matrix

    Args:
        U (jnp.ndarray): Parameters for unitary operator with shape of (..., 3)
        D (jnp.ndarray): Parameters for diagonal matrix with shape if (..., 2)

    Returns:
        jnp.ndarray: Hermitian matrix of shape (..., 2, 2)
    """
    # parametrize eigenvector matrix being unitary as in https://en.wikipedia.org/wiki/Unitary_matrix

    theta = U[..., 0]
    alpha = U[..., 1]
    beta = U[..., 2]

    lambda_1 = D[..., 0]
    lambda_2 = D[..., 1]

    q_00 = jnp.exp(1j * alpha) * jnp.cos(theta)
    q_01 = jnp.exp(1j * beta) * jnp.sin(theta)
    q_10 = -jnp.exp(-1j * beta) * jnp.sin(theta)
    q_11 = jnp.exp(-1j * alpha) * jnp.cos(theta)

    Q = jnp.zeros(U.shape[:-1] + (2, 2), dtype=jnp.complex_)
    Q = Q.at[..., 0, 0].set(q_00)
    Q = Q.at[..., 0, 1].set(q_01)
    Q = Q.at[..., 1, 0].set(q_10)
    Q = Q.at[..., 1, 1].set(q_11)

    # NOTE: Below is BUG
    # Q_dagger = Q.swapaxes(-2, -1).conj()
    # NOTE: Below is working
    Q_dagger = jnp.swapaxes(Q, -2, -1).conj()

    Diag = jnp.zeros(D.shape[:-1] + (2, 2), dtype=jnp.complex_)
    Diag = Diag.at[..., 0, 0].set(lambda_1)
    Diag = Diag.at[..., 1, 1].set(lambda_2)

    # Return Wos operator
    return jnp.matmul(Q, jnp.matmul(Diag, Q_dagger))

inspeqtor.models.shared.unitary

unitary(params: ndarray) -> ndarray

Create unitary matrix from parameters

Parameters:

Name Type Description Default
params ndarray

Parameters parametrize the unitary matrix

required

Returns:

Type Description
ndarray

jnp.ndarray: Unitary matrix of shape (..., 2, 2)

Source code in src/inspeqtor/v1/model.py
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
def unitary(params: jnp.ndarray) -> jnp.ndarray:
    """Create unitary matrix from parameters

    Args:
        params (jnp.ndarray): Parameters parametrize the unitary matrix

    Returns:
        jnp.ndarray: Unitary matrix of shape (..., 2, 2)

    """

    theta = params[..., 0]
    alpha = params[..., 1]
    beta = params[..., 2]
    psi = params[..., 3]

    q_00 = jnp.exp(1j * alpha) * jnp.cos(theta)
    q_01 = jnp.exp(1j * beta) * jnp.sin(theta)
    q_10 = -jnp.exp(-1j * beta) * jnp.sin(theta)
    q_11 = jnp.exp(-1j * alpha) * jnp.cos(theta)

    Q = jnp.zeros(params.shape[:-1] + (2, 2), dtype=jnp.complex_)
    Q = Q.at[..., 0, 0].set(q_00)
    Q = Q.at[..., 0, 1].set(q_01)
    Q = Q.at[..., 1, 0].set(q_10)
    Q = Q.at[..., 1, 1].set(q_11)

    psi_ = jnp.expand_dims(jnp.exp(1j * psi / 2), [-2, -1])

    return psi_ * Q

inspeqtor.models.shared.get_spam

get_spam(
    params: VariableDict,
) -> tuple[list[ExpectationValue], dict[str, ndarray]]
Source code in src/inspeqtor/v1/model.py
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
def get_spam(
    params: VariableDict,
) -> tuple[list[ExpectationValue], dict[str, jnp.ndarray]]:
    # https://forest-benchmarking.readthedocs.io/en/latest/examples/readout_error_estimation.html
    pair_map = {"+": "-", "-": "+", "0": "1", "1": "0", "r": "l", "l": "r"}
    observables = {"X": X, "Y": Y, "Z": Z}
    for pauli, matrix in observables.items():
        p_10 = params["AM"][pauli]["prob_10"]
        p_01 = params["AM"][pauli]["prob_01"]

        observables[pauli] = (
            matrix
            + (-2 * p_10 * plus_projectors[pauli])
            + (2 * p_01 * minus_projectors[pauli])
        )

    expvals = []
    order_expvals = get_default_expectation_values_order()
    for _expval in order_expvals:
        expval = ExpectationValue(
            initial_state=_expval.initial_state, observable=_expval.observable
        )
        # SP State Preparation error
        SP_correct_prob = params["SP"][_expval.initial_state]
        SP_incorrect_prob = 1 - SP_correct_prob
        expval.initial_density_matrix = SP_correct_prob * State.from_label(
            _expval.initial_state, dm=True
        ) + SP_incorrect_prob * State.from_label(
            pair_map[_expval.initial_state], dm=True
        )
        # AM, And Measurement error
        expval.observable_matrix = observables[_expval.observable]

        expvals.append(expval)

    return expvals, observables

inspeqtor.models.shared.model_parse_fn

model_parse_fn(key, value)

This is a parse function to be used with load_pytree_from_file function. The function will skip parsing config and will return as it is load from file.

Parameters:

Name Type Description Default
key Any

description

required
value Any

description

required

Returns:

Type Description

typing.Any: description

Source code in src/inspeqtor/v1/model.py
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
def model_parse_fn(key, value):
    """This is a parse function to be used with `load_pytree_from_file` function.
    The function will skip parsing config and will return as it is load from file.

    Args:
        key (typing.Any): _description_
        value (typing.Any): _description_

    Returns:
        typing.Any: _description_
    """
    if key == "config":
        return True, value
    elif isinstance(value, list):
        return True, jnp.array(value)
    elif isinstance(value, dict) and len(value) == 1 and "shape" in value:
        return True, ParamShape(shape=tuple(value["shape"]))
    elif isinstance(value, dict):
        return False, None
    else:
        return True, value

inspeqtor.models.shared.ModelData dataclass

Source code in src/inspeqtor/v1/model.py
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
@dataclass
class ModelData:
    params: typing.Any
    config: dict[str, typing.Any]

    def to_file(self, path: str | pathlib.Path):
        path = pathlib.Path(path)

        data = {
            "params": self.params,
            "config": self.config,
        }

        save_pytree_to_json(data, path)

    @classmethod
    def from_file(cls, path: str | pathlib.Path) -> typing.Self:
        data = load_pytree_from_json(path, model_parse_fn)

        return cls(
            params=data["params"],
            config=data["config"],
        )

    def __eq__(self, value):
        if not isinstance(value, type(self)):
            raise ValueError("The compared value is not Model object")

        try:
            chex.assert_trees_all_close(self.params, value.params)
        except AssertionError:
            return False

        return True if value.config == self.config else False

inspeqtor.models.shared.HistoryEntryV3 dataclass

Source code in src/inspeqtor/v1/model.py
584
585
586
587
588
589
@dataclass
class HistoryEntryV3:
    step: int
    loss: float | jnp.ndarray
    loop: str
    aux: dict[str, jnp.ndarray]

inspeqtor.models.shared.get_predict_expectation_value

get_predict_expectation_value(
    observable: dict[str, ndarray],
    unitaries: ndarray,
    order: list[ExpectationValue],
) -> ndarray

Calculate expectation values for given order

Parameters:

Name Type Description Default
observable operators

observable operator

required
unitaries ndarray

Unitary operators

required
order list[ExpectationValue]

Order of expectation value to be calculated

required

Returns:

Type Description
ndarray

jnp.ndarray: Expectation value with order as given with order

Source code in src/inspeqtor/v2/models/shared.py
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def get_predict_expectation_value(
    observable: dict[str, jnp.ndarray],
    unitaries: jnp.ndarray,
    order: list[ExpectationValue],
) -> jnp.ndarray:
    """Calculate expectation values for given order

    Args:
        observable (operators): observable operator
        unitaries (jnp.ndarray): Unitary operators
        order (list[ExpectationValue]): Order of expectation value to be calculated

    Returns:
        jnp.ndarray: Expectation value with order as given with `order`
    """

    return jnp.array(
        [
            calculate_exp(
                unitaries,
                observable[exp.observable],
                get_initial_state(exp.initial_state, dm=True),
            )
            for exp in order
        ]
    ).transpose()