> ## Documentation Index
> Fetch the complete documentation index at: https://docs.haiqu.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Experiment Tracking

> Organize, track, and manage your quantum experiments, circuits, and jobs in Haiqu SDK

## How to track your workloads

In the Haiqu SDK, you can make use of experiment tracking to keep your circuits and jobs organized. Every circuit you log and/or execute is connected to an experiment. So are the jobs that you run. Let's see how this works in the following simple example:

<Steps>
  <Step title="Initialize an Experiment">
    Create a new experiment to keep your circuits and jobs organized.

    ```python theme={null}
    from haiqu.sdk import haiqu

    # Login with your API key
    haiqu.login()

    # Create a new experiment
    haiqu.init("Hello Quantum World!")
    ```

    <Check>
      All your circuits and jobs will now be tracked under this experiment until you initialize a new one.
    </Check>
  </Step>

  <Step title="View and Switch Experiments">
    List your experiments and switch between them as needed.

    ```python theme={null}
    # View all experiments
    haiqu.list_experiments()

    # Switch to another experiment
    haiqu.init("Hello Again!")
    ```

    <Info>
      If you don't create an experiment, a default one is used automatically.
    </Info>
  </Step>

  <Step title="Log a Circuit">
    Add circuits to your experiment for tracking and re-use.

    ```python theme={null}
    from qiskit import QuantumCircuit

    # Create a Bell state circuit
    qc = QuantumCircuit(2)
    qc.h(0)
    qc.cx(0, 1)
    qc.measure_all()

    # Log the circuit
    haiqu_circuit = haiqu.log(qc, name="Bell state", description="A simple Bell state circuit")

    # View all circuits in the current experiment
    haiqu.list_circuits()
    ```

    <Check>
      You can now track, analyze, and re-run the logged circuits later.
    </Check>
  </Step>

  <Step title="Run a Job">
    Execute your logged circuit and track the job's progress.

    ```python theme={null}
    # Run the circuit on a simulator
    job = haiqu.run(
        circuits=haiqu_circuit,
        shots=1000,
        device_id="aer_simulator",
        job_name="Bell state execution",
        job_description="Executing Bell state on Aer simulator"
    )

    # Monitor progress
    job.progress()

    # Check status
    print(job.retrieve_status())

    # View all jobs in the current experiment 
    haiqu.list_jobs()
    ```

    <Check>
      Jobs are automatically linked to the experiment and circuit.
    </Check>
  </Step>

  <Step title="Retrieve Past Work">
    Easily load circuits or jobs from your history.

    ```python theme={null}
    # Get a circuit by ID
    loaded_circuit = haiqu.get_circuit(haiqu_circuit.id)
    haiqu.draw(loaded_circuit)

    # Get a job by ID and check status
    loaded_job = haiqu.get_job(job.id)
    loaded_job.retrieve_status()
    ```

    <Info>
      You can also search jobs by the circuit they executed using `haiqu.list_jobs(circuit=<circuit_id>)`.
    </Info>
  </Step>
</Steps>

<Note>
  All list objects methods, such as `haiqu.list_jobs`,`haiqu.list_circuits` \
  and `haiqu.list_experiments` by default render an HTML widget and return `None`.\
  **Use**`widget=False`**keyword argument in any of the aforementioned functions to return a list of objects**. Alternatively, use `pandas=True` to return a `pandas.DataFrame`object with the same information. See [SDK Reference | List Objects](https://docs.haiqu.ai/reference/core/list) for more information and examples.
</Note>

## Other use-cases

Here are some additional features you can use when working with experiments.

#### Retrieve lists of experiments, jobs and circuits as objects

In some cases, it is more useful to work with the list of objects, in order to do automated result tracking, advanced filtering, mass job cancellation, or when working outside of Jupyter. By default, when a function like `haiqu.list_experiments`, `haiqu.list_jobs` and `haiqu.list_circuits` is called, an HTML widget is rendered and displayed in the Jupyter cell output and `None` is returned. This can be changed by setting keyword argument `widget=False` in any of such functions. This makes the functions return `list[Experiment]`, `list[BaseJobModel]` and `list[CircuitModel]`, depending on the function. See [SDK Reference | List Objects](/reference/core/list) for more information and examples.  A few code snippets are provided below to showcase potential use-cases:

**Get list or pandas dataframe of experiments**

```python theme={null}
exps = haiqu.list_experiments(widget=False) # List of Experiment objects
df_exps = haiqu.list_experiments(widget=False, pandas=True) # Pandas DataFrame
```

**Check current status of all jobs**

```python theme={null}
job_statuses = {}
jobs = haiqu.list_jobs(widget=False)
for job in jobs:
  job_statuses[job.id] = job.retrieve_status()
```

#### List circuits from another experiment

By default, only circuits that belong to the current experiment are returned. It is possible to change this by specifying the `experiment_id` keyword argument. Use `haiqu.list_experiments` function to view available experiments.

```python theme={null}
haiqu.list_circuits(experiment_id=<experiment_id>)
```

#### Track job execution in real time

A blocking call that renders a HTML widget with logs that get updated in real time. The function only returns when the job finished running.

```python theme={null}
job.progress()
```

#### Access job logs

Access the current logs for a job as a string. Non-blocking.

```python theme={null}
print(job.logs)
```
