1. Home
  2. /
  3. Physical Lab Code Interfa...
  4. /
  5. solve_scan_lpu

solve_scan_lpu

Python
lsClient.solve_scan_lpu(
    matrixData=None,
    scanDictionary=None,
    waitForSolution=True,
    inputPath=None,
    num_runs=1,
    average_over=1,
    exposure_time=None,
    num_neighbors=1,
    effective_coupmat_translation_accuracy=10.0,
    effective_coupmat_translation_time=0.0,
)

Purpose: Run the Physical LPU on a complex coupling matrix while scanning user-defined phase settings over multiple steps. The scan is defined by scanDictionary, which specifies which lasers (pairs of indices) are scanned and what phase values to apply at each scan step.

Parameters

matrixData: numpy.ndarray, Required unless inputPath is used
Complex coupling matrix to upload and solve.

  • dtype: numpy.complex64
  • The dimension must be >= 5.
  • Matrix must be square
  • Sum of each row must be > 0 and < 1

scanDictionary: dict, Required unless inputPath is used
Scan specification dictionary. Must include the following keys:

num_of_steps: int
Number of scan steps (num_steps).

lasers_to_scan: numpy.ndarray
Laser index pairs to scan. Each row is a pair of indices.
Shape: [num_pairs, 2]
Example: [[1, 1], [4, 4], ...]

phases_to_scan: numpy.ndarray
Phase values for each scanned pair across all scan steps.
Shape: [num_pairs, num_steps]
dtype: numpy.float32

waitForSolution: bool, Optional; default = True
When True, blocks until the physical solver finishes and returns the final solution dictionary.
When False, returns immediately with a request descriptor suitable for get_solution_sync.

inputPath: str | None, Optional; default = None
Advanced: reference to a pre-uploaded input. When provided, matrixData and scanDictionary are not uploaded here.

num_runs: int, Optional; default = 1
Number of independent physical runs (experiments) to perform.

average_over: int, Optional; default = 1
Number of measurements averaged per run.

exposure_time: int | None, Optional; default = None
Camera exposure time in microseconds. If set, it is passed to the hardware as an integer value.

num_neighbors: int, Optional; default = 1
Neighbor distance used for interference control (hardware/service dependent).

effective_coupmat_translation_accuracy: float, Optional; default = 10.0
Translation stopping criterion based on accuracy (ETA).

effective_coupmat_translation_time: float, Optional; default = 0.0
Translation stopping criterion based on time (ETT).

Returns (synchronous, when waitForSolution=True)

Return type: dict

command: str
Always "LPU".

data: dict
Contains the solver output.

solutions: list
Length = num_experiments.
Each entry corresponds to one experiment batch.

solutions[i]: list[dict]
Length = num_steps.
One entry per scan step.

solutions[i][j]: dict
Laser state for scan step j.

phase_problem: ndarray[float]
Shape: [num_lasers]

phase_reference: ndarray[float]
Shape: [num_lasers]

energy_problem: ndarray[float]
Shape: [num_lasers]

energy_reference: ndarray[float]
Shape: [num_lasers]

contrast_problem: ndarray[float]
Shape: [num_lasers]

contrast_reference: ndarray[float]
Shape: [num_lasers]

snr_problem: ndarray[float]
Shape: [num_lasers]

snr_reference: ndarray[float]
Shape: [num_lasers]

image_problem_list: ndarray[int]
Shape: [num_lasers, height, width]

image_reference_list: ndarray[int]
Shape: [num_lasers, height, width]

solver_running_time: float
Total solver processing time (seconds).

exposure_time: int
Camera exposure time used (microseconds).

creation_time: str
Format: "DD-MM-YYYY-HH-MM-SS-microseconds"

reqTime: str

id: str

userId: str

receivedTime: str

effective_coupmat: ndarray[complex64]
Shape: [num_lasers, num_lasers]

warnings: None
Present and set to None when no warnings exist.

Returns (asynchronous, when waitForSolution=False)
Return type: dict
A request descriptor dictionary returned by the service. Pass this dictionary unchanged to get_solution_sync to retrieve the solution later.

id: str
reqTime: str ("DD-MM-YYYY-HH-MM-SS-microseconds")
receivedTime: str
Notes and comments
Phases to scan must be a 2D array even if you are scanning only one laser

Examples

Constructing scanDictionary

Python
import numpy as np

size = 5
coupling_matrix = 0.5 * numpy.eye(size, dtype=numpy.complex64)
coupling = (1-0.5)/2
for i in range(size - 1):
    coupling_matrix[i,i+1] = coupling
    coupling_matrix[i+1,i] = coupling

num_steps = 16

# lasers to scan
lasers_to_scan = np.array([[1, 1]])

# phases to scan for each pair of indices over num_steps
phases_to_scan = np.linspace(0,2*np.pi , num_steps)
phases_to_scan = np.tile(phases_to_scan, (lasers_to_scan.shape[0], 1))
 
scan_dictionary = {
    "num_of_steps": num_steps,
    "lasers_to_scan": lasers_to_scan,
    "phases_to_scan": phases_to_scan,
}

Running the solver scan

Python

# Run scan solve (synchronous)
result = lsClient.solve_scan_lpu(
    matrixData=coupling_matrix ,
    scanDictionary=scan_dictionary,
    num_runs=2,
    average_over=1,
    exposure_time=600,
    waitForSolution=True,
)

Accessing the results

Python
# Top-level metadata
print("Command:", res["command"])
print("Solver time:", res["data"]["solver_running_time"])
print("Exposure time:", res["data"]["exposure_time"])

# Access experiment list
experiments = res["data"]["solutions"]

for exp_idx, experiment in enumerate(experiments):
    print(f"\nExperiment {exp_idx + 1}")
    print(f"Number of scan steps: {len(experiment)}")

    for scan_idx, scan_step in enumerate(experiment):

        phase_problem = scan_step["phase_problem"]
        contrast_problem = scan_step["contrast_problem"]
        snr_problem = scan_step["snr_problem"]

        print(f"  Scan step {scan_idx + 1}")
        print(f"    Phase shape: {phase_problem.shape}")
        print(f"    Contrast mean: {contrast_problem.mean():.4f}")
        print(f"    SNR mean: {snr_problem.mean():.4f}")

# Effective coupling matrix (if needed)
effective_coupmat = res["effective_coupmat"]
print("\nEffective coupling matrix shape:", effective_coupmat.shape)


How can we help?