Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Bug fix when nstates=1; when expects is None; small changes to plotting#11

Merged
dkweiss31 merged 13 commits intodkweiss31:mainfrom
cyrus-baker:branch_fix
Jun 30, 2025
Merged

Bug fix when nstates=1; when expects is None; small changes to plotting#11
dkweiss31 merged 13 commits intodkweiss31:mainfrom
cyrus-baker:branch_fix

Conversation

@cyrus-baker
Copy link
Contributor

  1. fix bug when plot_expects when expects is None;
  2. fix dim calculation in PropagatorInfidelity;
  3. fix bug when initial state is only one in CoherentInfidelity

…ug when plot expects in propagator where expects is None; 2. fix dim calculation in PropagatorInfidelity; 3. fix bug when initial state is only one in CoherentInfidelity
qontrol/cost.py Outdated
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is necessary, see here for the function this calls which already specifies the last two axes

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes, this bug is caused by squeeze, not by trace

Copy link
Owner

@dkweiss31 dkweiss31 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this PR @littlebaker! I've left some comments. I'm wondering if you might be able to adjust your solution when expects is None to avoid just having an empty plot. Could we use different default plotters for the propogator functionality? Additionally, you've uncovered a few bugs, and I'm wondering if you can add test coverage for those use cases so that they shouldn't show up again?

@cyrus-baker
Copy link
Contributor Author

Sure, I will remove the empty plot when expects is None. As for the plotters functionality, I think we may need further discussion.

@cyrus-baker
Copy link
Contributor Author

Sure, I will add some test code

Comment on lines 107 to 118
# check plotter
if plotter is None:
if (
model.exp_ops is not None
and len(model.exp_ops) > 0
and not isinstance(model, SEPropagatorModel)
and not isinstance(model, MEPropagatorModel)
):
plotter = DefaultPlotter()
else:
plotter = Plotter([plot_fft, plot_controls])

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like what you're going for here. I think what this is pointing to is that we need one more layer of abstraction. The base Model class shouldn't have exp_ops as an attribute, since the propagator models don't have it. I'm thinking of something like

class Model(eqx.Module):
    H_function: callable
    tsave_function: callable

    def __call__(
            self,
            parameters: Array | dict,
            method: Method = Tsit5(),  # noqa B008
            gradient: Gradient | None = None,
            options: dq.Options = dq.Options(),  # noqa B008
    ) -> tuple[Result, TimeQArray]:
        raise NotImplementedError


class SolveModel(Model):
    exp_ops: Array | None


class PropagatorModel(Model):
    pass

Would you be able to make these changes to the model file? Then the check above could become much simpler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, that will be a good idea.

@dkweiss31
Copy link
Owner

I think we're getting close! One quick thing: there are a lot of .pyc files that are part of this PR: can you remove them?

@cyrus-baker
Copy link
Contributor Author

Ok, sure. I will remove them.

@cyrus-baker cyrus-baker requested a review from dkweiss31 June 16, 2025 17:10
@cyrus-baker
Copy link
Contributor Author

Sorry, wrong operation, I did not finished.

@cyrus-baker
Copy link
Contributor Author

def plot_controls(
    ax: Axes, _expects: Array | None, model: Model, parameters: Array | dict
) -> Axes:
    """Plot the Hamiltonian prefactors, usually corresponding to controls."""
    ax.set_facecolor('none')
    H = model.H_function(parameters)
    tsave = model.tsave_function(parameters)
    controls = get_controls(H, tsave)
    H_labels = [f'$H_{idx}$' for idx in range(len(controls))]
    for idx, control in enumerate(controls):
        ax.plot(tsave, np.real(control) / 2 / np.pi, label=H_labels[idx])
    ax.legend(loc='lower right', framealpha=0.0)
    ax.set_ylabel('pulse amplitude [GHz]')
    ax.set_xlabel('time [ns]')
    return ax

why np.real(control) / 2 / np.pi has / 2 / np.pi ? I think 2 pi should be multiplied in Hamiltonians?

@dkweiss31
Copy link
Owner

Right, this is a mostly arbitrary choice that the controls included the 2pis, so that I needed to divide by 2pi when plotting. You are right though that not everyone will do this and it can be unexpected for users, so I'm happy to change this default behavior (though one can of course use their own custom Plotter

lishengyong added 6 commits June 26, 2025 10:44
@dkweiss31
Copy link
Owner

@littlebaker is this PR ready for my review? (I do still see a .json and .pyc file that shouldn't be included)

@cyrus-baker
Copy link
Contributor Author

Oh, sorry for that. I will check it again.

@dkweiss31 dkweiss31 changed the title Bug fix Bug fix when nstates=1; when expects is None; small changes to plotting Jun 30, 2025
Copy link
Owner

@dkweiss31 dkweiss31 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @littlebaker ! Everything LGTM. I will let the ci run and then we can merge :). Congrats on your first contribution!!

@dkweiss31 dkweiss31 merged commit 327fcae into dkweiss31:main Jun 30, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments