Repository: sandialabs/pyGSTi (language: python)

Issue:
Qibo API Change
The qibo devs pushed a new release to pypi on 9/3, and in this new release the seed kwarg has been removed from all of the Channel objects. There wasn't any explanation on the corresponding commit (SHA d182b9b if you're curious) on the rationale for this change, unfortunately.

As it stands the qibo evotype in pygsti won't work fully until we address this. I'm guessing we can either update the evotypes on our end to work around this or else update the requirements to use the previous release at the expense of whatever other new features/enhancements were included in this new one.

@enielse and @sserita, you both are the ones in the know on the qibo integration work, any thoughts on how to proceed?



Discussion / hints:
This has been currently avoided by limiting Qibo to version 0.1.7 in setup.py. Long-term, we probably want to reach out to the Qibo developers and understand why they made this change. It seems harder to get deterministic weak forward simulation now (since the RNG was important for sampling from operator "unravelings").
We will likely deprecate the Qibo interface in the upcoming release, and remove it in a future release. Qibo is moving in a different direction (towards a full stack package rather than just a forward simulator) and is no longer a good fit for a third-party integration.

Fix patch:
diff --git a/optional-requirements.txt b/optional-requirements.txt
index bbd007812..b238c472c 100644
--- a/optional-requirements.txt
+++ b/optional-requirements.txt
@@ -10,5 +10,4 @@ cython
 cvxopt
 cvxpy
 seaborn
-qibo
 packaging
diff --git a/packages/pygsti/__init__.py b/packages/pygsti/__init__.py
deleted file mode 100644
index dc3770519..000000000
--- a/packages/pygsti/__init__.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#***************************************************************************************************
-# Copyright 2015, 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
-# Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain rights
-# in this software.
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
-# in compliance with the License.  You may obtain a copy of the License at
-# http://www.apache.org/licenses/LICENSE-2.0 or in the LICENSE file in the root pyGSTi directory.
-#***************************************************************************************************
-""" This is a placeholder script to warn pyGSTi users of a change in project structure.
-
-As of pyGSTi v0.9.9, the pyGSTi source directory has been moved from
-`/packages/pygsti` to `/pygsti`. For most users, this change should be
-completely imperceptible. However, if you have installed pyGSTi from
-source in development mode, i.e. using `pip install -e .`, your pyGSTi
-installation may now be broken.
-"""
-
-import warnings
-from pathlib import Path
-
-pygsti_root = Path(__file__).absolute().parent.parent.parent
-
-instructions = """
-\u001b[31m\u001b[1mIf you are seeing this message, you need to reinstall pyGSTi!\u001b[0m
-Open a shell and run the following commands:
-
-1. `cd {pygsti_root}`
-2. `pip install -e .[complete]`
-3. `python -c "import pygsti"`
-
-After following these instructions, if you still see this message,
-check to make sure that you don't have a GST.pth file located in
-your local site-packages directory (try running `find ~ -name GST.pth`).
-
-After removing any GST.pth files, if you're still seeing this
-message, leave a bug report for the pyGSTi developers at
-https://github.com/pyGSTio/pyGSTi/issues
-""".format(pygsti_root=pygsti_root)
-
-warnings.warn(__doc__ + instructions)
-raise NotImplementedError()
diff --git a/pygsti/algorithms/directx.py b/pygsti/algorithms/directx.py
deleted file mode 100644
index c08a7b65a..000000000
--- a/pygsti/algorithms/directx.py
+++ /dev/null
@@ -1,711 +0,0 @@
-"""
-Functions for generating Direct-(LGST, MC2GST, MLGST) models
-"""
-#***************************************************************************************************
-# Copyright 2015, 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
-# Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain rights
-# in this software.
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
-# in compliance with the License.  You may obtain a copy of the License at
-# http://www.apache.org/licenses/LICENSE-2.0 or in the LICENSE file in the root pyGSTi directory.
-#***************************************************************************************************
-
-import warnings as _warnings
-_warnings.warn("pygsti.algorithms.directx is deprecated and will be removed in pyGSTi 0.9.13")
-
-from pygsti.algorithms import core as _core
-from pygsti import baseobjs as _baseobjs
-from pygsti.baseobjs import Label
-from pygsti import circuits as _circuits
-from pygsti import objectivefns as _objfns
-from pygsti.modelmembers.operations import FullArbitraryOp as _FullArbitraryOp
-
-
-def model_with_lgst_circuit_estimates(
-        circuits_to_estimate, dataset, prep_fiducials, meas_fiducials,
-        target_model, include_target_ops=True, op_label_aliases=None,
-        guess_model_for_gauge=None, circuit_labels=None, svd_truncate_to=None,
-        verbosity=0):
-    """
-    Constructs a model that contains LGST estimates for `circuits_to_estimate`.
-
-    For each circuit in `circuits_to_estimate`, the constructed model
-    contains the LGST estimate for s as separate gate, labeled either by
-    the corresponding element of circuit_labels or by the tuple of s itself.
-
-    Parameters
-    ----------
-    circuits_to_estimate : list of Circuits or tuples
-        The circuits to estimate using LGST
-
-    dataset : DataSet
-        The data to use for LGST
-
-    prep_fiducials : list of Circuits
-       Fiducial circuits used to construct an informationally complete
-       effective preparation.
-
-    meas_fiducials : list of Circuits
-       Fiducial circuits used to construct an informationally complete
-       effective measurement.
-
-    target_model : Model
-        A model used by LGST to specify which operation labels should be estimated,
-        a guess for which gauge these estimates should be returned in, and
-        used to simplify circuits.
-
-    include_target_ops : bool, optional
-        If True, the operation labels in target_model will be included in the
-        returned model.
-
-    op_label_aliases : dictionary, optional
-        Dictionary whose keys are operation label "aliases" and whose values are tuples
-        corresponding to what that operation label should be expanded into before querying
-        the dataset. Defaults to the empty dictionary (no aliases defined)
-        e.g. opLabelAliases['Gx^3'] = ('Gx','Gx','Gx')
-
-    guess_model_for_gauge : Model, optional
-        A model used to compute a gauge transformation that is applied to
-        the LGST estimates.  This gauge transformation is computed such that
-        if the estimated gates matched the model given, then the gate
-        matrices would match, i.e. the gauge would be the same as
-        the model supplied. Defaults to the target_model.
-
-    circuit_labels : list of strings, optional
-        A list of labels in one-to-one correspondence with the
-        circuit in `circuits_to_estimate`.  These labels are
-        the keys to access the operation matrices in the returned
-        Model, i.e. op_matrix = returned_model[op_label]
-
-    svd_truncate_to : int, optional
-        The Hilbert space dimension to truncate the operation matrices to using
-        a SVD to keep only the largest svdToTruncateTo singular values of
-        the I_tildle LGST matrix. Zero means no truncation.
-        Defaults to dimension of `target_model`.
-
-    verbosity : int, optional
-        Verbosity value to send to `run_lgst(...)` call.
-
-    Returns
-    -------
-    Model
-        A model containing LGST estimates for all the requested
-        circuits and possibly the gates in target_model.
-    """
-    opLabels = []  # list of operation labels for LGST to estimate
-    if op_label_aliases is None: aliases = {}
-    else: aliases = op_label_aliases.copy()
-
-    #Add circuits to estimate as aliases
-    if circuit_labels is not None:
-        assert(len(circuit_labels) == len(circuits_to_estimate))
-        for opLabel, opStr in zip(circuit_labels, circuits_to_estimate):
-            aliases[opLabel] = opStr.replace_layers_with_aliases(op_label_aliases)
-            opLabels.append(opLabel)
-    else:
-        for opStr in circuits_to_estimate:
-            newLabel = 'G' + '.'.join(map(str, tuple(opStr)))
-            aliases[newLabel] = opStr.replace_layers_with_aliases(op_label_aliases)  # use circuit tuple as label
-            opLabels.append(newLabel)
-
-    #Add target model labels (not aliased) if requested
-    if include_target_ops and target_model is not None:
-        for targetOpLabel in target_model.operations:
-            if targetOpLabel not in opLabels:  # very unlikely that this is false
-                opLabels.append(targetOpLabel)
-
-    return _core.run_lgst(dataset, prep_fiducials, meas_fiducials, target_model,
-                          opLabels, aliases, guess_model_for_gauge,
-                          svd_truncate_to, verbosity)
-
-
-def direct_lgst_model(circuit_to_estimate, circuit_label, dataset,
-                      prep_fiducials, meas_fiducials, target_model,
-                      op_label_aliases=None, svd_truncate_to=None, verbosity=0):
-    """
-    Constructs a model of LGST estimates for target gates and circuit_to_estimate.
-
-    Parameters
-    ----------
-    circuit_to_estimate : Circuit or tuple
-        The single circuit to estimate using LGST
-
-    circuit_label : string
-        The label for the estimate of `circuit_to_estimate`.
-        i.e. op_matrix = returned_model[op_label]
-
-    dataset : DataSet
-        The data to use for LGST
-
-    prep_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective preparation.
-
-    meas_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective measurement.
-
-    target_model : Model
-        The target model used by LGST to extract operation labels and an initial gauge
-
-    op_label_aliases : dictionary, optional
-        Dictionary whose keys are operation label "aliases" and whose values are tuples
-        corresponding to what that operation label should be expanded into before querying
-        the dataset. Defaults to the empty dictionary (no aliases defined)
-        e.g. opLabelAliases['Gx^3'] = ('Gx','Gx','Gx')
-
-    svd_truncate_to : int, optional
-        The Hilbert space dimension to truncate the operation matrices to using
-        a SVD to keep only the largest svdToTruncateTo singular values of
-        the I_tildle LGST matrix.  Zero means no truncation.
-        Defaults to dimension of `target_model`.
-
-    verbosity : int, optional
-        Verbosity value to send to `run_lgst(...)` call.
-
-    Returns
-    -------
-    Model
-        A model containing LGST estimates of `circuit_to_estimate`
-        and the gates of `target_model`.
-    """
-    return model_with_lgst_circuit_estimates(
-        [circuit_to_estimate], dataset, prep_fiducials, meas_fiducials, target_model,
-        True, op_label_aliases, None, [circuit_label], svd_truncate_to,
-        verbosity)
-
-
-def direct_lgst_models(circuits, dataset, prep_fiducials, meas_fiducials, target_model,
-                       op_label_aliases=None, svd_truncate_to=None, verbosity=0):
-    """
-    Constructs a dictionary with keys == circuits and values == Direct-LGST Models.
-
-    Parameters
-    ----------
-    circuits : list of Circuit or tuple objects
-        The circuits to estimate using LGST.  The elements of this list
-        are the keys of the returned dictionary.
-
-    dataset : DataSet
-        The data to use for all LGST estimates.
-
-    prep_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective preparation.
-
-    meas_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective measurement.
-
-    target_model : Model
-        The target model used by LGST to extract operation labels and an initial gauge
-
-    op_label_aliases : dictionary, optional
-        Dictionary whose keys are operation label "aliases" and whose values are tuples
-        corresponding to what that operation label should be expanded into before querying
-        the dataset. Defaults to the empty dictionary (no aliases defined)
-        e.g. opLabelAliases['Gx^3'] = ('Gx','Gx','Gx')
-
-    svd_truncate_to : int, optional
-        The Hilbert space dimension to truncate the operation matrices to using
-        a SVD to keep only the largest svdToTruncateTo singular values of
-        the I_tildle LGST matrix. Zero means no truncation.
-        Defaults to dimension of `target_model`.
-
-    verbosity : int, optional
-        Verbosity value to send to run_lgst(...) call.
-
-    Returns
-    -------
-    dict
-        A dictionary that relates each circuit to a Model containing the LGST
-        estimate of that circuit's action (as a SPAM-less operation sequence)
-        stored under the operation label "GsigmaLbl", along with LGST estimates
-        of the gates in `target_model`.
-    """
-    printer = _baseobjs.VerbosityPrinter.create_printer(verbosity)
-
-    directLGSTmodels = {}
-    printer.log("--- Direct LGST precomputation ---")
-    with printer.progress_logging(1):
-        for i, sigma in enumerate(circuits):
-            printer.show_progress(i, len(circuits), prefix="--- Computing model for string -", suffix='---')
-            directLGSTmodels[sigma] = direct_lgst_model(
-                sigma, "GsigmaLbl", dataset, prep_fiducials, meas_fiducials, target_model,
-                op_label_aliases, svd_truncate_to, verbosity)
-    return directLGSTmodels
-
-
-def direct_mc2gst_model(circuit_to_estimate, circuit_label, dataset,
-                        prep_fiducials, meas_fiducials, target_model,
-                        op_label_aliases=None, svd_truncate_to=None,
-                        min_prob_clip_for_weighting=1e-4,
-                        prob_clip_interval=(-1e6, 1e6), verbosity=0):
-    """
-    Constructs a model of LSGST estimates for target gates and circuit_to_estimate.
-
-    Starting with a Direct-LGST estimate for circuit_to_estimate, runs LSGST
-    using the same strings that LGST would have used to estimate circuit_to_estimate
-    and each of the target gates.  That is, LSGST is run with strings of the form:
-
-    1. prep_fiducial
-    2. meas_fiducial
-    3. prep_fiducial + meas_fiducial
-    4. prep_fiducial + single_gate + meas_fiducial
-    5. prep_fiducial + circuit_to_estimate + meas_fiducial
-
-    and the resulting Model estimate is returned.
-
-    Parameters
-    ----------
-    circuit_to_estimate : Circuit
-        The single circuit to estimate using LSGST
-
-    circuit_label : string
-        The label for the estimate of `circuit_to_estimate`.
-        i.e. op_matrix = returned_mode[op_label]
-
-    dataset : DataSet
-        The data to use for LGST
-
-    prep_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective preparation.
-
-    meas_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective measurement.
-
-    target_model : Model
-        The target model used by LGST to extract operation labels and an initial gauge
-
-    op_label_aliases : dictionary, optional
-        Dictionary whose keys are operation label "aliases" and whose values are tuples
-        corresponding to what that operation label should be expanded into before querying
-        the dataset. Defaults to the empty dictionary (no aliases defined)
-        e.g. opLabelAliases['Gx^3'] = ('Gx','Gx','Gx')
-
-    svd_truncate_to : int, optional
-        The Hilbert space dimension to truncate the operation matrices to using
-        a SVD to keep only the largest svdToTruncateTo singular values of
-        the I_tildle LGST matrix. Zero means no truncation.
-        Defaults to dimension of `target_model`.
-
-    min_prob_clip_for_weighting : float, optional
-        defines the clipping interval for the statistical weight used
-        within the chi^2 function (see chi2fn).
-
-    prob_clip_interval : 2-tuple, optional
-        (min,max) to clip probabilities to within Model probability
-        computation routines (see Model.bulk_fill_probs)
-
-    verbosity : int, optional
-        Verbosity value to send to run_lgst(...) and do_mc2gst(...) calls.
-
-    Returns
-    -------
-    Model
-        A model containing LSGST estimates of `circuit_to_estimate`
-        and the gates of `target_model`.
-    """
-    direct_lgst = model_with_lgst_circuit_estimates(
-        [circuit_to_estimate], dataset, prep_fiducials, meas_fiducials, target_model,
-        True, op_label_aliases, None, [circuit_label], svd_truncate_to, verbosity)
-
-    # LEXICOGRAPHICAL VS MATRIX ORDER
-    circuits = prep_fiducials + meas_fiducials + [prepC + measC for prepC in prep_fiducials
-                                                  for measC in meas_fiducials]
-    for opLabel in direct_lgst.operations:
-        circuits.extend([prepC + _circuits.Circuit((opLabel,)) + measC
-                         for prepC in prep_fiducials for measC in meas_fiducials])
-
-    aliases = {} if (op_label_aliases is None) else op_label_aliases.copy()
-    aliases[circuit_label] = circuit_to_estimate.replace_layers_with_aliases(op_label_aliases)
-
-    obuilder = _objfns.Chi2Function.builder(regularization={'min_prob_clip_for_weighting': min_prob_clip_for_weighting},
-                                            penalties={'prob_clip_interval': prob_clip_interval})
-    bulk_circuits = _circuits.CircuitList(circuits, aliases)
-    _, direct_lsgst = _core.run_gst_fit_simple(dataset, direct_lgst, bulk_circuits, optimizer=None,
-                                               objective_function_builder=obuilder, resource_alloc=None,
-                                               verbosity=verbosity)
-
-    return direct_lsgst
-
-
-def direct_mc2gst_models(circuits, dataset, prep_fiducials, meas_fiducials,
-                         target_model, op_label_aliases=None,
-                         svd_truncate_to=None, min_prob_clip_for_weighting=1e-4,
-                         prob_clip_interval=(-1e6, 1e6), verbosity=0):
-    """
-    Constructs a dictionary with keys == circuits and values == Direct-LSGST Models.
-
-    Parameters
-    ----------
-    circuits : list of Circuit or tuple objects
-        The circuits to estimate using LSGST.  The elements of this list
-        are the keys of the returned dictionary.
-
-    dataset : DataSet
-        The data to use for all LGST and LSGST estimates.
-
-    prep_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective preparation.
-
-    meas_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective measurement.
-
-    target_model : Model
-        The target model used by LGST to extract operation labels and an initial gauge
-
-    op_label_aliases : dictionary, optional
-        Dictionary whose keys are operation label "aliases" and whose values are tuples
-        corresponding to what that operation label should be expanded into before querying
-        the dataset. Defaults to the empty dictionary (no aliases defined)
-        e.g. opLabelAliases['Gx^3'] = ('Gx','Gx','Gx')
-
-    svd_truncate_to : int, optional
-        The Hilbert space dimension to truncate the operation matrices to using
-        a SVD to keep only the largest svdToTruncateTo singular values of
-        the I_tildle LGST matrix. Zero means no truncation.
-        Defaults to dimension of `target_model`.
-
-    min_prob_clip_for_weighting : float, optional
-        defines the clipping interval for the statistical weight used
-        within the chi^2 function (see chi2fn).
-
-    prob_clip_interval : 2-tuple, optional
-        (min,max) to clip probabilities to within Model probability
-        computation routines (see Model.bulk_fill_probs)
-
-    verbosity : int, optional
-        Verbosity value to send to run_lgst(...) and do_mc2gst(...) calls.
-
-    Returns
-    -------
-    dict
-        A dictionary that relates each circuit to a Model containing the LGST
-        estimate of that circuit's action (as a SPAM-less operation sequence)
-        stored under the operation label "GsigmaLbl", along with LSGST estimates
-        of the gates in `target_model`.
-    """
-    printer = _baseobjs.VerbosityPrinter.create_printer(verbosity)
-    directLSGSTmodels = {}
-    printer.log("--- Direct LSGST precomputation ---")
-    with printer.progress_logging(1):
-        for i, sigma in enumerate(circuits):
-            printer.show_progress(i, len(circuits), prefix="--- Computing model for string-", suffix='---')
-            directLSGSTmodels[sigma] = direct_mc2gst_model(
-                sigma, 
-                Label('GsigmaLbl') if sigma.line_labels == ('*',) else Label('GsigmaLbl', sigma.line_labels), 
-                dataset, prep_fiducials, meas_fiducials, target_model,
-                op_label_aliases, svd_truncate_to, min_prob_clip_for_weighting,
-                prob_clip_interval, verbosity)
-
-    return directLSGSTmodels
-
-
-def direct_mlgst_model(circuit_to_estimate, circuit_label, dataset,
-                       prep_fiducials, meas_fiducials, target_model,
-                       op_label_aliases=None, svd_truncate_to=None, min_prob_clip=1e-6,
-                       prob_clip_interval=(-1e6, 1e6), verbosity=0):
-    """
-    Constructs a model of MLEGST estimates for target gates and circuit_to_estimate.
-
-    Starting with a Direct-LGST estimate for circuit_to_estimate, runs MLEGST
-    using the same strings that LGST would have used to estimate circuit_to_estimate
-    and each of the target gates.  That is, MLEGST is run with strings of the form:
-
-    1. prep_fiducial
-    2. meas_fiducial
-    3. prep_fiducial + meas_fiducial
-    4. prep_fiducial + singleGate + meas_fiducial
-    5. prep_fiducial + circuit_to_estimate + meas_fiducial
-
-    and the resulting Model estimate is returned.
-
-    Parameters
-    ----------
-    circuit_to_estimate : Circuit or tuple
-        The single circuit to estimate using LSGST
-
-    circuit_label : string
-        The label for the estimate of `circuit_to_estimate`.
-        i.e. `op_matrix = returned_model[op_label]`
-
-    dataset : DataSet
-        The data to use for LGST
-
-    prep_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective preparation.
-
-    meas_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective measurement.
-
-    target_model : Model
-        The target model used by LGST to extract operation labels and an initial gauge
-
-    op_label_aliases : dictionary, optional
-        Dictionary whose keys are operation label "aliases" and whose values are tuples
-        corresponding to what that operation label should be expanded into before querying
-        the dataset. Defaults to the empty dictionary (no aliases defined)
-        e.g. opLabelAliases['Gx^3'] = ('Gx','Gx','Gx')
-
-    svd_truncate_to : int, optional
-        The Hilbert space dimension to truncate the operation matrices to using
-        a SVD to keep only the largest svdToTruncateTo singular values of
-        the I_tildle LGST matrix. Zero means no truncation.
-        Defaults to dimension of `target_model`.
-
-    min_prob_clip : float, optional
-        defines the minimum probability "patch point" used
-        within the logl function.
-
-    prob_clip_interval : 2-tuple, optional
-        (min,max) to clip probabilities to within Model probability
-        computation routines (see Model.bulk_fill_probs)
-
-    verbosity : int, optional
-        Verbosity value to send to run_lgst(...) and do_mlgst(...) calls.
-
-    Returns
-    -------
-    Model
-        A model containing MLEGST estimates of `circuit_to_estimate`
-        and the gates of `target_model`.
-    """
-    direct_lgst = model_with_lgst_circuit_estimates(
-        [circuit_to_estimate], dataset, prep_fiducials, meas_fiducials, target_model,
-        True, op_label_aliases, None, [circuit_label], svd_truncate_to, verbosity)
-
-    # LEXICOGRAPHICAL VS MATRIX ORDER
-    circuits = prep_fiducials + meas_fiducials + [prepC + measC for prepC in prep_fiducials
-                                                  for measC in meas_fiducials]
-    for opLabel in direct_lgst.operations:
-        circuits.extend([prepC + _circuits.Circuit((opLabel,)) + measC
-                         for prepC in prep_fiducials for measC in meas_fiducials])
-
-    aliases = {} if (op_label_aliases is None) else op_label_aliases.copy()
-    aliases[circuit_label] = circuit_to_estimate.replace_layers_with_aliases(op_label_aliases)
-
-    obuilder = _objfns.PoissonPicDeltaLogLFunction.builder(regularization={'min_prob_clip': min_prob_clip},
-                                                           penalties={'prob_clip_interval': prob_clip_interval})
-    bulk_circuits = _circuits.CircuitList(circuits, aliases)
-    _, direct_mlegst = _core.run_gst_fit_simple(dataset, direct_lgst, bulk_circuits, optimizer=None,
-                                                objective_function_builder=obuilder, resource_alloc=None,
-                                                verbosity=verbosity)
-
-    return direct_mlegst
-
-
-def direct_mlgst_models(circuits, dataset, prep_fiducials, meas_fiducials, target_model,
-                        op_label_aliases=None, svd_truncate_to=None, min_prob_clip=1e-6,
-                        prob_clip_interval=(-1e6, 1e6), verbosity=0):
-    """
-    Constructs a dictionary with keys == circuits and values == Direct-MLEGST Models.
-
-    Parameters
-    ----------
-    circuits : list of Circuit or tuple objects
-        The circuits to estimate using MLEGST.  The elements of this list
-        are the keys of the returned dictionary.
-
-    dataset : DataSet
-        The data to use for all LGST and LSGST estimates.
-
-    prep_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective preparation.
-
-    meas_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective measurement.
-
-    target_model : Model
-        The target model used by LGST to extract operation labels and an initial gauge
-
-    op_label_aliases : dictionary, optional
-        Dictionary whose keys are operation label "aliases" and whose values are tuples
-        corresponding to what that operation label should be expanded into before querying
-        the dataset. Defaults to the empty dictionary (no aliases defined)
-        e.g. opLabelAliases['Gx^3'] = ('Gx','Gx','Gx')
-
-    svd_truncate_to : int, optional
-        The Hilbert space dimension to truncate the operation matrices to using
-        a SVD to keep only the largest svdToTruncateTo singular values of
-        the I_tildle LGST matrix. Zero means no truncation.
-        Defaults to dimension of `target_model`.
-
-    min_prob_clip : float, optional
-        defines the minimum probability "patch point" used
-        within the logl function.
-
-    prob_clip_interval : 2-tuple, optional
-        (min,max) to clip probabilities to within Model probability
-        computation routines (see Model.bulk_fill_probs)
-
-    verbosity : int, optional
-        Verbosity value to send to run_lgst(...) and do_mlgst(...) calls.
-
-    Returns
-    -------
-    dict
-        A dictionary that relates each circuit to a Model containing the LGST
-        estimate of that circuit's action (as a SPAM-less operation sequence)
-        stored under the operation label "GsigmaLbl", along with MLEGST estimates
-        of the gates in `target_model`.
-    """
-    printer = _baseobjs.VerbosityPrinter.create_printer(verbosity)
-    directMLEGSTmodels = {}
-    printer.log("--- Direct MLEGST precomputation ---")
-    with printer.progress_logging(1):
-        for i, sigma in enumerate(circuits):
-            printer.show_progress(i, len(circuits), prefix="--- Computing model for string ", suffix="---")
-            directMLEGSTmodels[sigma] = direct_mlgst_model(
-                sigma, 
-                Label('GsigmaLbl') if sigma.line_labels == ('*',) else Label('GsigmaLbl', sigma.line_labels),
-                dataset, prep_fiducials, meas_fiducials, target_model,
-                op_label_aliases, svd_truncate_to, min_prob_clip,
-                prob_clip_interval, verbosity)
-
-    return directMLEGSTmodels
-
-
-def focused_mc2gst_model(circuit_to_estimate, circuit_label, dataset,
-                         prep_fiducials, meas_fiducials, start_model,
-                         op_label_aliases=None, min_prob_clip_for_weighting=1e-4,
-                         prob_clip_interval=(-1e6, 1e6), verbosity=0):
-    """
-    Constructs a model containing a single LSGST estimate of `circuit_to_estimate`.
-
-    Starting with `start_model`, run LSGST with the same circuits that LGST
-    would use to estimate `circuit_to_estimate`.  That is, LSGST is run with
-    strings of the form:  prep_fiducial + circuit_to_estimate + meas_fiducial
-    and return the resulting Model.
-
-    Parameters
-    ----------
-    circuit_to_estimate : Circuit or tuple
-        The single circuit to estimate using LSGST
-
-    circuit_label : string
-        The label for the estimate of `circuit_to_estimate`.
-        i.e. `op_matrix = returned_model[op_label]`
-
-    dataset : DataSet
-        The data to use for LGST
-
-    prep_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective preparation.
-
-    meas_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective measurement.
-
-    start_model : Model
-        The model to seed LSGST with. Often times obtained via LGST.
-
-    op_label_aliases : dictionary, optional
-        Dictionary whose keys are operation label "aliases" and whose values are tuples
-        corresponding to what that operation label should be expanded into before querying
-        the dataset. Defaults to the empty dictionary (no aliases defined)
-        e.g. opLabelAliases['Gx^3'] = ('Gx','Gx','Gx')
-
-    min_prob_clip_for_weighting : float, optional
-        defines the clipping interval for the statistical weight used
-        within the chi^2 function (see chi2fn).
-
-    prob_clip_interval : 2-tuple, optional
-        (min,max) to clip probabilities to within Model probability
-        computation routines (see Model.bulk_fill_probs)
-
-    verbosity : int, optional
-        Verbosity value to send do_mc2gst(...) call.
-
-    Returns
-    -------
-    Model
-        A model containing LSGST estimate of `circuit_to_estimate`.
-    """
-    circuits = [prepC + circuit_to_estimate + measC for prepC in prep_fiducials for measC in meas_fiducials]
-
-    obuilder = _objfns.Chi2Function.builder(regularization={'min_prob_clip_for_weighting': min_prob_clip_for_weighting},
-                                            penalties={'prob_clip_interval': prob_clip_interval})
-    bulk_circuits = _circuits.CircuitList(circuits, op_label_aliases)
-    _, focused_lsgst = _core.run_gst_fit_simple(dataset, start_model, bulk_circuits, optimizer=None,
-                                                objective_function_builder=obuilder, resource_alloc=None,
-                                                verbosity=verbosity)
-
-    focused_lsgst.operations[circuit_label] = _FullArbitraryOp(
-        focused_lsgst.sim.product(circuit_to_estimate))  # add desired string as a separate labeled gate
-    return focused_lsgst
-
-
-def focused_mc2gst_models(circuits, dataset, prep_fiducials, meas_fiducials,
-                          start_model, op_label_aliases=None,
-                          min_prob_clip_for_weighting=1e-4,
-                          prob_clip_interval=(-1e6, 1e6), verbosity=0):
-    """
-    Constructs a dictionary with keys == circuits and values == Focused-LSGST Models.
-
-    Parameters
-    ----------
-    circuits : list of Circuit or tuple objects
-        The circuits to estimate using LSGST.  The elements of this list
-        are the keys of the returned dictionary.
-
-    dataset : DataSet
-        The data to use for all LGST and LSGST estimates.
-
-    prep_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective preparation.
-
-    meas_fiducials : list of Circuits
-        Fiducial circuits used to construct an informationally complete
-        effective measurement.
-
-    start_model : Model
-        The model to seed LSGST with. Often times obtained via LGST.
-
-    op_label_aliases : dictionary, optional
-        Dictionary whose keys are operation label "aliases" and whose values are tuples
-        corresponding to what that operation label should be expanded into before querying
-        the dataset. Defaults to the empty dictionary (no aliases defined)
-        e.g. opLabelAliases['Gx^3'] = ('Gx','Gx','Gx')
-
-    min_prob_clip_for_weighting : float, optional
-        defines the clipping interval for the statistical weight used
-        within the chi^2 function (see chi2fn).
-
-    prob_clip_interval : 2-tuple, optional
-        (min,max) to clip probabilities to within Model probability
-        computation routines (see Model.bulk_fill_probs)
-
-    verbosity : int, optional
-        Verbosity value to send to do_mc2gst(...) call.
-
-    Returns
-    -------
-    dict
-        A dictionary that relates each circuit to a Model containing the
-        LSGST estimate of that circuit's action, stored under the
-        operation label "GsigmaLbl".
-    """
-
-    printer = _baseobjs.VerbosityPrinter.create_printer(verbosity)
-    focusedLSGSTmodels = {}
-    printer.log("--- Focused LSGST precomputation ---")
-    with printer.progress_logging(1):
-        for i, sigma in enumerate(circuits):
-            printer.show_progress(i, len(circuits), prefix="--- Computing model for string", suffix='---')
-            focusedLSGSTmodels[sigma] = focused_mc2gst_model(
-                sigma, 
-                Label('GsigmaLbl') if sigma.line_labels == ('*',) else Label('GsigmaLbl', sigma.line_labels),
-                dataset, prep_fiducials, meas_fiducials, start_model,
-                op_label_aliases, min_prob_clip_for_weighting, prob_clip_interval, verbosity)
-    return focusedLSGSTmodels
diff --git a/pygsti/evotypes/qibo/__init__.py b/pygsti/evotypes/qibo/__init__.py
deleted file mode 100644
index 1db9158df..000000000
--- a/pygsti/evotypes/qibo/__init__.py
+++ /dev/null
@@ -1,33 +0,0 @@
-"""
-An evolution type that uses the 3rd-party 'qibo' package.
-"""
-#***************************************************************************************************
-# Copyright 2015, 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
-# Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain rights
-# in this software.
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
-# in compliance with the License.  You may obtain a copy of the License at
-# http://www.apache.org/licenses/LICENSE-2.0 or in the LICENSE file in the root pyGSTi directory.
-#***************************************************************************************************
-
-densitymx_mode = False
-nshots = 1000
-
-
-def _get_densitymx_mode():
-    return densitymx_mode
-
-
-def _get_nshots():
-    return nshots
-
-
-def _get_minimal_space():
-    return minimal_space
-
-
-minimal_space = 'Hilbert'
-from .povmreps import *
-from .effectreps import *
-from .opreps import *
-from .statereps import *
diff --git a/pygsti/evotypes/qibo/effectreps.py b/pygsti/evotypes/qibo/effectreps.py
deleted file mode 100644
index dac57e1b5..000000000
--- a/pygsti/evotypes/qibo/effectreps.py
+++ /dev/null
@@ -1,78 +0,0 @@
-"""
-POVM effect representation classes for the `qibo` evolution type.
-"""
-#***************************************************************************************************
-# Copyright 2015, 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
-# Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain rights
-# in this software.
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
-# in compliance with the License.  You may obtain a copy of the License at
-# http://www.apache.org/licenses/LICENSE-2.0 or in the LICENSE file in the root pyGSTi directory.
-#***************************************************************************************************
-import numpy as _np
-
-from .. import basereps as _basereps
-from pygsti.baseobjs.statespace import StateSpace as _StateSpace
-
-from . import _get_densitymx_mode, _get_nshots
-
-
-class EffectRep(_basereps.EffectRep):
-    def __init__(self, state_space):
-        self.state_space = _StateSpace.cast(state_space)
-
-    @property
-    def nqubits(self):
-        return self.state_space.num_qubits
-
-
-class EffectRepComputational(EffectRep):
-    def __init__(self, zvals, basis, state_space):
-        self.zvals = zvals
-        self.basis = basis
-        super(EffectRepComputational, self).__init__(state_space)
-
-
-class EffectRepConjugatedState(EffectRep):
-
-    def __init__(self, state_rep):
-        self.state_rep = state_rep
-        super(EffectRepConjugatedState, self).__init__(state_rep.state_space)
-
-    def probability(self, state):
-        # compute <s2|s1>
-        assert(_get_densitymx_mode() is True), "Can only use EffectRepConjugatedState when densitymx_mode == True!"
-
-        initial_state = state.qibo_state
-        effect_state = self.state_rep.qibo_state
-        if effect_state.ndim == 1:  # b/c qibo_state can be either a vector or density mx
-            #Promote this state vector to a density matrix to use it as a POVM effect
-            effect_state = _np.kron(effect_state[:, None], effect_state.conjugate()[None, :])
-        assert(effect_state.ndim == 2)  # density matrices
-
-        qibo_circuit = state.qibo_circuit
-        results = qibo_circuit(initial_state)
-        return _np.real_if_close(effect_state.ravel().conjugate() @ results.state().ravel())
-
-    def to_dense(self, on_space):
-        return self.state_rep.to_dense(on_space)
-
-    @property
-    def basis(self):
-        # (all qibo effect reps need to have a .basis property)
-        return self.state_rep.basis
-
-
-class EffectRepComposed(EffectRep):
-    def __init__(self, op_rep, effect_rep, op_id, state_space):
-        self.op_rep = op_rep
-        self.effect_rep = effect_rep
-        self.op_id = op_id
-
-        self.state_space = _StateSpace.cast(state_space)
-        assert(self.state_space.is_compatible_with(effect_rep.state_space))
-
-        super(EffectRepComposed, self).__init__(effect_rep.state_space)
-
-    def probability(self, state):
-        return self.effect_rep.probability(self.op_rep.acton(state))
diff --git a/pygsti/evotypes/qibo/opreps.py b/pygsti/evotypes/qibo/opreps.py
deleted file mode 100644
index 78144684a..000000000
--- a/pygsti/evotypes/qibo/opreps.py
+++ /dev/null
@@ -1,376 +0,0 @@
-"""
-Operation representation classes for the `qibo` evolution type.
-"""
-#***************************************************************************************************
-# Copyright 2015, 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
-# Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain rights
-# in this software.
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
-# in compliance with the License.  You may obtain a copy of the License at
-# http://www.apache.org/licenses/LICENSE-2.0 or in the LICENSE file in the root pyGSTi directory.
-#***************************************************************************************************
-
-import itertools as _itertools
-import copy as _copy
-from functools import partial as _partial
-
-import numpy as _np
-from scipy.sparse.linalg import LinearOperator
-from numpy.random import RandomState as _RandomState
-
-from . import _get_minimal_space
-from .statereps import StateRep as _StateRep
-from .. import basereps as _basereps
-from pygsti.baseobjs.statespace import StateSpace as _StateSpace
-from pygsti.baseobjs.basis import Basis as _Basis
-from ...tools import jamiolkowski as _jt
-from ...tools import basistools as _bt
-from ...tools import internalgates as _itgs
-from ...tools import optools as _ot
-
-
-try:
-    import qibo as _qibo
-
-    std_qibo_creation_fns = {  # functions that create the desired op given qubit indices & gate args
-        'Gi': _qibo.gates.I,
-        'Gxpi2': _partial(_qibo.gates.RX, theta=_np.pi / 2, trainable=False),
-        'Gypi2': _partial(_qibo.gates.RY, theta=_np.pi / 2, trainable=False),
-        'Gzpi2': _partial(_qibo.gates.RZ, theta=_np.pi / 2, trainable=False),
-        'Gxpi': _qibo.gates.X,
-        'Gypi': _qibo.gates.Y,
-        'Gzpi': _qibo.gates.Z,
-        'Gxmpi2': _partial(_qibo.gates.RX, theta=-_np.pi / 2, trainable=False),
-        'Gympi2': _partial(_qibo.gates.RY, theta=-_np.pi / 2, trainable=False),
-        'Gzmpi2': _partial(_qibo.gates.RZ, theta=-_np.pi / 2, trainable=False),
-        'Gh': _qibo.gates.H,
-        'Gp': _qibo.gates.S,
-        'Gpdag': _partial(_qibo.gates.U1, theta=-_np.pi / 2, trainable=False),
-        'Gt': _qibo.gates.T,
-        'Gtdag': _partial(_qibo.gates.U1, theta=-_np.pi / 4, trainable=False),
-        'Gcphase': _qibo.gates.CZ,
-        'Gcnot': _qibo.gates.CNOT,
-        'Gswap': _qibo.gates.SWAP,
-        #'Gzr': _qibo.gates.RZ,  # takes (q, theta)
-        #'Gczr': _qibo.gates.CRZ,  # takes (q0, q1, theta)
-        'Gx': _partial(_qibo.gates.RX, theta=_np.pi / 2, trainable=False),
-        'Gy': _partial(_qibo.gates.RY, theta=_np.pi / 2, trainable=False),
-        'Gz': _partial(_qibo.gates.RZ, theta=_np.pi / 2, trainable=False)
-    }
-except (ImportError, AttributeError):  # AttributeError if an early version of qibo without some of the above gates
-    _qibo = None
-
-
-class OpRep(_basereps.OpRep):
-    def __init__(self, state_space):
-        self.state_space = state_space
-
-    @property
-    def dim(self):
-        return self.state_space.udim
-
-    def create_qibo_ops_on(self, qubit_indices):
-        raise NotImplementedError("Derived classes must implement this!")
-
-    def acton(self, state):
-        c = state.qibo_circuit.copy()
-        # TODO: change below to: sole_tensor_product_block_labels
-        for qibo_op in self.create_qibo_ops_on(self.state_space.tensor_product_block_labels(0)):
-            c.add(qibo_op)
-        return _StateRep(c, state.qibo_state.copy(), state.state_space)
-
-    def adjoint_acton(self, state):
-        raise NotImplementedError()
-
-    def acton_random(self, state, rand_state):
-        return self.acton(state)  # default is to ignore rand_state
-
-    def adjoint_acton_random(self, state, rand_state):
-        return self.adjoint_acton(state)  # default is to ignore rand_state
-
-#    def aslinearoperator(self):
-#        def mv(v):
-#            if v.ndim == 2 and v.shape[1] == 1: v = v[:, 0]
-#            in_state = _StateRepDensePure(_np.ascontiguousarray(v, complex), self.state_space, basis=None)
-#            return self.acton(in_state).to_dense('Hilbert')
-#
-#        def rmv(v):
-#            if v.ndim == 2 and v.shape[1] == 1: v = v[:, 0]
-#            in_state = _StateRepDensePure(_np.ascontiguousarray(v, complex), self.state_space, basis=None)
-#            return self.adjoint_acton(in_state).to_dense('Hilbert')
-#        return LinearOperator((self.dim, self.dim), matvec=mv, rmatvec=rmv)  # transpose, adjoint, dot, matmat?
-
-    def copy(self):
-        return _copy.deepcopy(self)
-
-
-class OpRepDenseUnitary(OpRep):
-    def __init__(self, mx, basis, state_space):
-        state_space = _StateSpace.cast(state_space)
-        if mx is None:
-            mx = _np.identity(state_space.udim, complex)
-        assert(mx.ndim == 2 and mx.shape[0] == state_space.udim)
-        self.basis = basis
-        self.base = _np.require(mx, requirements=['OWNDATA', 'C_CONTIGUOUS'])
-        super(OpRepDenseUnitary, self).__init__(state_space)
-
-    def create_qibo_ops_on(self, qubit_indices):
-        return [_qibo.gates.UnitaryChannel([1.0], [(qubit_indices, self.base)], seed=None)]
-
-    def base_has_changed(self):
-        pass  # nothing needed
-
-    def to_dense(self, on_space):
-        if on_space == 'Hilbert' or (on_space == 'minimal' and _get_minimal_space() == 'Hilbert'):
-            return self.base
-        elif on_space == 'HilbertSchmidt' or (on_space == 'minimal' and _get_minimal_space() == 'HilbertSchmidt'):
-            return _ot.unitary_to_superop(self.base, self.basis)
-        else:
-            raise ValueError("Invalid `on_space` argument: %s" % str(on_space))
-
-    def __str__(self):
-        return "OpRepDenseUnitary:\n" + str(self.base)
-
-
-class OpRepDenseSuperop(OpRep):
-    def __init__(self, mx, basis, state_space):
-        state_space = _StateSpace.cast(state_space)
-        if mx is None:
-            mx = _np.identity(state_space.dim, 'd')
-        assert(mx.ndim == 2 and mx.shape[0] == state_space.dim)
-        self.basis = basis
-        assert(self.basis is not None), "Qibo evotype requires OpRepDenseSuperop be given a basis (to get Kraus ops!)"
-
-        self.base = _np.require(mx, requirements=['OWNDATA', 'C_CONTIGUOUS'])
-        super(OpRepDenseSuperop, self).__init__(state_space)
-        self.base_has_changed()  # sets self.kraus_ops
-
-    def base_has_changed(self):
-        #recompute Kraus ops for creating qibo op
-        superop_mx = self.base; d = int(_np.round(_np.sqrt(superop_mx.shape[0])))
-        std_basis = _Basis.cast('std', superop_mx.shape[0])
-        choi_mx = _jt.jamiolkowski_iso(superop_mx, self.basis, std_basis) * d  # see NOTE below
-        evals, evecs = _np.linalg.eig(choi_mx)
-        assert(all([ev > -1e-7 for ev in evals])), \
-            "Cannot compute Kraus decomposition of non-positive-definite superoperator (within OpRepDenseSuperop!)"
-        self.kraus_ops = [evecs[:, i].reshape(d, d) * _np.sqrt(ev) for i, ev in enumerate(evals) if abs(ev) > 1e-7]
-
-    def to_dense(self, on_space):
-        if not (on_space == 'HilbertSchmidt' or (on_space == 'minimal' and _get_minimal_space() == 'HilbertSchmidt')):
-            raise ValueError("'densitymx_slow' evotype cannot produce Hilbert-space ops!")
-        return self.base
-
-    def create_qibo_ops_on(self, qubit_indices):
-        return [_qibo.gates.KrausChannel([(qubit_indices, Ki) for Ki in self.kraus_ops])]
-
-    def __str__(self):
-        return "OpRepDenseSuperop:\n" + str(self.base)
-
-    def copy(self):
-        return OpRepDenseSuperop(self.base.copy(), self.basis, self.state_space)
-
-
-class OpRepStandard(OpRep):
-    def __init__(self, name, basis, state_space):
-        self.name = name
-        if self.name not in std_qibo_creation_fns:
-            raise ValueError("Standard name '%s' is not available in 'qibo' evotype" % self.name)
-
-        self.basis = basis  # used anywhere?
-        self.creation_fn = std_qibo_creation_fns[name]
-        # create the desired op given qubit indices & gate args
-
-        super(OpRepStandard, self).__init__(state_space)
-
-    def create_qibo_ops_on(self, qubit_indices):
-        return [self.creation_fn(*qubit_indices)]
-
-
-#class OpRepStochastic(OpRepDense):
-# - maybe we could add this, but it wouldn't be a "dense" op here,
-#   perhaps we need to change API?
-
-
-class OpRepComposed(OpRep):
-    # exactly the same as densitymx case
-    def __init__(self, factor_op_reps, state_space):
-        #assert(len(factor_op_reps) > 0), "Composed gates must contain at least one factor gate!"
-        self.factor_reps = factor_op_reps
-        super(OpRepComposed, self).__init__(state_space)
-
-    def create_qibo_ops_on(self, qubit_indices):
-        return list(_itertools.chain(*[f.create_qibo_ops_on(qubit_indices) for f in self.factor_reps]))
-
-    def reinit_factor_op_reps(self, new_factor_op_reps):
-        self.factors_reps = new_factor_op_reps
-
-
-# This might work, but we won't need it unless we get OpRepExpErrorgen, etc, working.
-#class OpRepSum(OpRep):
-#    # exactly the same as densitymx case
-#    def __init__(self, factor_reps, state_space):
-#        #assert(len(factor_reps) > 0), "Composed gates must contain at least one factor gate!"
-#        self.factor_reps = factor_reps
-#        super(OpRepSum, self).__init__(state_space)
-#
-#    def acton(self, state):
-#        """ Act this gate map on an input state """
-#        output_state = _StateRepDensePure(_np.zeros(state.data.shape, complex), state.state_space, state.basis)
-#        for f in self.factor_reps:
-#            output_state.data += f.acton(state).data
-#        return output_state
-#
-#    def adjoint_acton(self, state):
-#        """ Act the adjoint of this operation matrix on an input state """
-#        output_state = _StateRepDensePure(_np.zeros(state.data.shape, complex), state.state_space, state.basis)
-#        for f in self.factor_reps:
-#            output_state.data += f.adjoint_acton(state).data
-#        return output_state
-#
-#    def acton_random(self, state, rand_state):
-#        """ Act this gate map on an input state """
-#        output_state = _StateRepDensePure(_np.zeros(state.data.shape, complex), state.state_space, state.basis)
-#        for f in self.factor_reps:
-#            output_state.data += f.acton_random(state, rand_state).data
-#        return output_state
-#
-#    def adjoint_acton_random(self, state, rand_state):
-#        """ Act the adjoint of this operation matrix on an input state """
-#        output_state = _StateRepDensePure(_np.zeros(state.data.shape, complex), state.state_space, state.basis)
-#        for f in self.factor_reps:
-#            output_state.data += f.adjoint_acton_random(state, rand_state).data
-#        return output_state
-
-
-class OpRepEmbedded(OpRep):
-
-    def __init__(self, state_space, target_labels, embedded_rep):
-        self.target_labels = target_labels
-        self.embedded_rep = embedded_rep
-        super(OpRepEmbedded, self).__init__(state_space)
-
-    def create_qibo_ops_on(self, qubit_indices):
-        # TODO: change below to: sole_tensor_product_block_labels
-        assert(qubit_indices == self.state_space.tensor_product_block_labels(0))
-        return self.embedded_rep.create_qibo_ops_on(self.target_labels)
-
-
-#REMOVE
-#class OpRepExpErrorgen(OpRep):
-#
-#    def __init__(self, errorgen_rep):
-#        state_space = errorgen_rep.state_space
-#        self.errorgen_rep = errorgen_rep
-#        super(OpRepExpErrorgen, self).__init__(state_space)
-#
-#    def errgenrep_has_changed(self, onenorm_upperbound):
-#        pass
-#
-#    def acton(self, state):
-#        raise AttributeError("Cannot currently act with statevec.OpRepExpErrorgen - for terms only!")
-#
-#    def adjoint_acton(self, state):
-#        raise AttributeError("Cannot currently act with statevec.OpRepExpErrorgen - for terms only!")
-
-
-class OpRepRepeated(OpRep):
-    def __init__(self, rep_to_repeat, num_repetitions, state_space):
-        state_space = _StateSpace.cast(state_space)
-        self.repeated_rep = rep_to_repeat
-        self.num_repetitions = num_repetitions
-        super(OpRepRepeated, self).__init__(state_space)
-
-    def create_qibo_ops_on(self, qubit_indices):
-        return [self.repeated_rep.create_qibo_ops_on(qubit_indices)] * self.num_repetitions
-
-
-#REMOVE
-#class OpRepLindbladErrorgen(OpRep):
-#    def __init__(self, lindblad_coefficient_blocks, state_space):
-#        super(OpRepLindbladErrorgen, self).__init__(state_space)
-#        self.Lterms = None
-#        self.Lterm_coeffs = None
-#        self.lindblad_coefficient_blocks = lindblad_coefficient_blocks
-
-
-class OpRepKraus(OpRep):
-    def __init__(self, basis, kraus_reps, state_space):
-        self.basis = basis
-        self.kraus_reps = kraus_reps  # superop reps in this evotype (must be reps of *this* evotype)
-        assert(all([isinstance(rep, OpRepDenseUnitary) for rep in kraus_reps]))
-        state_space = _StateSpace.cast(state_space)
-        assert(self.basis.dim == state_space.dim)
-        super(OpRepKraus, self).__init__(state_space)
-
-    def create_qibo_ops_on(self, qubit_indices):
-        kraus_ops = [Krep.base for Krep in self.kraus_reps]
-        kraus_norms = list(map(_np.linalg.norm, kraus_ops))
-        return [_qibo.gates.KrausChannel([(qubit_indices, Ki)
-                                          for Ki, nrm in zip(kraus_ops, kraus_norms) if nrm > 1e-7])]
-
-    def __str__(self):
-        return "OpRepKraus with ops\n" + str(self.kraus_reps)
-
-    def copy(self):
-        return OpRepKraus(self.basis, list(self.kraus_reps), None, self.state_space)
-
-    def to_dense(self, on_space):
-        assert(on_space == 'HilbertSchmidt' or (on_space == 'minimal' and _get_minimal_space() == 'HilbertSchmidt')), \
-            'Can only compute OpRepKraus.to_dense on HilbertSchmidt space!'
-        return sum([rep.to_dense(on_space) for rep in self.kraus_reps])
-
-
-class OpRepRandomUnitary(OpRep):
-    def __init__(self, basis, unitary_rates, unitary_reps, seed_or_state, state_space):
-        self.basis = basis
-        self.unitary_reps = unitary_reps
-        self.unitary_rates = unitary_rates.copy()
-
-        if isinstance(seed_or_state, _RandomState):
-            self.rand_state = seed_or_state
-        else:
-            self.rand_state = _RandomState(seed_or_state)
-
-        self.state_space = _StateSpace.cast(state_space)
-        assert(self.basis.dim == self.state_space.dim)
-        super(OpRepRandomUnitary, self).__init__(state_space)
-
-    def create_qibo_ops_on(self, qubit_indices):
-        return [_qibo.gates.UnitaryChannel(self.unitary_rates, [(qubit_indices, Uk.to_dense('Hilbert'))
-                                                                for Uk in self.unitary_reps],
-                                           seed=self.rand_state.randint(0, 2**30))]  # HARDCODED 2**30!! (max seed)
-
-    def __str__(self):
-        return "OpRepRandomUnitary:\n" + " rates: " + str(self.unitary_rates)  # maybe show ops too?
-
-    def copy(self):
-        return OpRepRandomUnitary(self.basis, self.unitary_rates, list(self.unitary_reps),
-                                  self.rand_state, self.state_space)
-
-    def update_unitary_rates(self, rates):
-        self.unitary_rates[:] = rates
-
-    def to_dense(self, on_space):
-        assert(on_space == 'HilbertSchmidt')  # below code only works in this case
-        return sum([rate * rep.to_dense(on_space) for rate, rep in zip(self.unitary_rates, self.unitary_reps)])
-
-
-class OpRepStochastic(OpRepRandomUnitary):
-
-    def __init__(self, stochastic_basis, basis, initial_rates, seed_or_state, state_space):
-        self.rates = initial_rates
-        self.stochastic_basis = stochastic_basis
-        rates = [1 - sum(initial_rates)] + list(initial_rates)
-        reps = [OpRepDenseUnitary(bel, basis, state_space) for bel in stochastic_basis.elements]
-        assert(len(reps) == len(rates))
-
-        state_space = _StateSpace.cast(state_space)
-        assert(basis.dim == state_space.dim)
-        self.basis = basis
-
-        super(OpRepStochastic, self).__init__(basis, _np.array(rates, 'd'), reps, seed_or_state, state_space)
-
-    def update_rates(self, rates):
-        unitary_rates = [1 - sum(rates)] + list(rates)
-        self.rates[:] = rates
-        self.update_unitary_rates(unitary_rates)
diff --git a/pygsti/evotypes/qibo/povmreps.py b/pygsti/evotypes/qibo/povmreps.py
deleted file mode 100644
index ef28ce916..000000000
--- a/pygsti/evotypes/qibo/povmreps.py
+++ /dev/null
@@ -1,98 +0,0 @@
-"""
-POVM representation classes for the `qibo` evolution type.
-"""
-#***************************************************************************************************
-# Copyright 2015, 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
-# Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain rights
-# in this software.
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
-# in compliance with the License.  You may obtain a copy of the License at
-# http://www.apache.org/licenses/LICENSE-2.0 or in the LICENSE file in the root pyGSTi directory.
-#***************************************************************************************************
-
-import os as _os
-import re as _re
-import subprocess as _sp
-import tempfile as _tf
-import numpy as _np
-
-from .. import basereps as _basereps
-from . import _get_densitymx_mode, _get_nshots
-from pygsti.baseobjs.statespace import StateSpace as _StateSpace
-from pygsti.baseobjs.outcomelabeldict import OutcomeLabelDict as _OutcomeLabelDict
-
-try:
-    import qibo as _qibo
-except ImportError:
-    _qibo = None
-
-
-class POVMRep(_basereps.POVMRep):
-    def __init__(self):
-        super(POVMRep, self).__init__()
-
-
-class ComputationalPOVMRep(POVMRep):
-    def __init__(self, nqubits, qubit_filter):
-        self.nqubits = nqubits
-        self.qubit_filter = qubit_filter
-        super(ComputationalPOVMRep, self).__init__()
-
-    #REMOVE
-    #def sample_outcome(self, state, rand_state):
-    #    chp_ops = state.chp_ops
-    #
-    #    povm_qubits = _np.array(range(self.nqubits))
-    #    for iqubit in povm_qubits:
-    #        if self.qubit_filter is None or iqubit in self.qubit_filter:
-    #            chp_ops.append(f'm {iqubit}')
-    #
-    #    # TODO: Make sure this handles intermediate measurements
-    #    outcomes, _ = self._run_chp_ops(chp_ops)
-    #    outcome = ''.join(outcomes)
-    #    outcome_label = _OutcomeLabelDict.to_outcome(outcome)
-    #    return outcome_label
-
-    def probabilities(self, state, rand_state, effect_labels):
-        qibo_circuit = state.qibo_circuit
-        initial_state = state.qibo_state
-        # TODO: change below to: sole_tensor_product_block_labels
-        qubits_to_measure = state.state_space.tensor_product_block_labels(0) \
-            if (self.qubit_filter is None) else self.qubit_filter
-
-        gatetypes_requiring_shots = set(('UnitaryChannel', 'PauliNoiseChannel',
-                                         'ResetChannel', 'ThermalRelaxationChannel'))
-        circuit_requires_shots = len(gatetypes_requiring_shots.intersection(set(qibo_circuit.gate_types.keys()))) > 0
-        if _get_densitymx_mode() or circuit_requires_shots is False:
-            #then we can use QIBO's exact .probabilities call:
-            results = qibo_circuit(initial_state)
-            prob_tensor = results.probabilities(qubits_to_measure)
-
-            probs = [prob_tensor[tuple(map(int, effect_lbl))] for effect_lbl in effect_labels]
-            # Above map & int converts, e.g., '01' -> (0,1)
-        else:
-            #we must use built-in weak fwdsim
-            qibo_circuit.add(_qibo.gates.M(*qubits_to_measure))
-            nshots = _get_nshots()
-            results = qibo_circuit(initial_state, nshots=nshots)
-            freqs = results.frequencies(binary=True)
-            probs = [freqs[effect_lbl] / nshots for effect_lbl in effect_labels]
-    
-        return probs
-
-
-class ComposedPOVMRep(POVMRep):
-    def __init__(self, errmap_rep, base_povm_rep, state_space):
-        self.errmap_rep = errmap_rep
-        self.base_povm_rep = base_povm_rep
-        self.state_space = state_space
-        super(ComposedPOVMRep, self).__init__()
-
-#REMOVE
-#    def sample_outcome(self, state, rand_state):
-#        state = self.errmap_rep.acton_random(state, rand_state)
-#        return self.base_povm_rep.sample_outcome(state)
-
-    def probabilities(self, state, rand_state, effect_labels):
-        state = self.errmap_rep.acton_random(state, rand_state)
-        return self.base_povm_rep.probabilities(state, rand_state, effect_labels)
diff --git a/pygsti/evotypes/qibo/statereps.py b/pygsti/evotypes/qibo/statereps.py
deleted file mode 100644
index e35193953..000000000
--- a/pygsti/evotypes/qibo/statereps.py
+++ /dev/null
@@ -1,174 +0,0 @@
-"""
-State representations for "qibo" evolution type.
-"""
-#***************************************************************************************************
-# Copyright 2015, 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
-# Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain rights
-# in this software.
-# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
-# in compliance with the License.  You may obtain a copy of the License at
-# http://www.apache.org/licenses/LICENSE-2.0 or in the LICENSE file in the root pyGSTi directory.
-#***************************************************************************************************
-
-import numpy as _np
-import functools as _functools
-
-from .. import basereps as _basereps
-from . import _get_densitymx_mode, _get_minimal_space
-from pygsti.baseobjs.statespace import StateSpace as _StateSpace
-from pygsti.baseobjs.basis import Basis as _Basis
-from pygsti.tools import internalgates as _itgs
-from pygsti.tools import basistools as _bt
-from pygsti.tools import optools as _ot
-
-try:
-    from ...tools import fastcalc as _fastcalc
-except ImportError:
-    _fastcalc = None
-
-try:
-    import qibo as _qibo
-except ImportError:
-    _qibo = None
-
-
-class StateRep(_basereps.StateRep):
-    def __init__(self, qibo_circuit, qibo_state, state_space):
-        self.qibo_circuit = qibo_circuit
-        self.qibo_state = qibo_state
-        self.state_space = _StateSpace.cast(state_space)
-        assert(self.qibo_circuit is None or self.state_space.num_qubits == self.qibo_circuit.nqubits), \
-            'Number-of-qubits mismatch between state space and circuit for "qubit" evotype'
-
-    @property
-    def num_qubits(self):
-        return self.state_space.num_qubits
-
-    def copy(self):
-        return StateRep(self.qibo_circuit, self.qibo_state, self.state_space)
-
-    def actionable_staterep(self):
-        # return a state rep that can be acted on by op reps or mapped to
-        # a probability/amplitude by POVM effect reps.
-        return self  # for most classes, the rep itself is actionable
-
-
-class StateRepDensePure(StateRep):
-    def __init__(self, purevec, state_space, basis):
-        state_space = _StateSpace.cast(state_space)
-        qibo_circuit = _qibo.models.Circuit(state_space.num_qubits, density_matrix=_get_densitymx_mode())
-        self.basis = basis
-        super(StateRepDensePure, self).__init__(qibo_circuit, purevec, state_space)
-
-    @property
-    def base(self):
-        return self.qibo_state
-
-    def base_has_changed(self):
-        pass
-
-    def to_dense(self, on_space):
-        if on_space == 'Hilbert' or (on_space == 'minimal' and _get_minimal_space() == 'Hilbert'):
-            return self.base
-        elif on_space == 'HilbertSchmidt' or (on_space == 'minimal' and _get_minimal_space() == 'HilbertSchmidt'):
-            return _bt.change_basis(_ot.state_to_dmvec(self.base), 'std', self.basis)
-        else:
-            raise ValueError("Invalid `on_space` argument: %s" % str(on_space))
-
-
-class StateRepDense(StateRep):
-    def __init__(self, data, state_space, basis):
-        assert(_get_densitymx_mode() is True), "Must set pygsti.evotypes.qibo.densitymx_mode=True to use dense states!"
-        state_space = _StateSpace.cast(state_space)
-        qibo_circuit = _qibo.models.Circuit(state_space.num_qubits, density_matrix=True)
-        self.basis = basis
-        self.std_basis = _Basis.cast('std', state_space.dim)  # the basis the qibo expects
-        self.data = data
-        self.udim = state_space.udim
-        qibo_state = _bt.change_basis(data, basis, self.std_basis).reshape((self.udim, self.udim))
-        super(StateRepDense, self).__init__(qibo_circuit, qibo_state, state_space)
-
-    @property
-    def base(self):
-        return self.data  # state in self.basis (not self.std_basis)
-
-    def base_has_changed(self):
-        self.qibo_state = _bt.change_basis(self.data, self.basis, self.std_basis).reshape((self.udim, self.udim))
-
-    def to_dense(self, on_space):
-        if not (on_space == 'HilbertSchmidt' or (on_space == 'minimal' and _get_minimal_space() == 'HilbertSchmidt')):
-            raise ValueError("'densitymx' evotype cannot produce Hilbert-space ops!")
-        return self.data
-
-
-class StateRepComputational(StateRep):
-    def __init__(self, zvals, basis, state_space):
-        assert all([nm in ('pp', 'PP') for nm in basis.name.split('*')]), \
-            "Only Pauli basis is allowed for 'chp' evotype"
-
-        #Convert zvals to dense vec:
-        factor_dim = 2
-        v0 = _np.array((1, 0), complex)  # '0' qubit state as complex state vec
-        v1 = _np.array((0, 1), complex)  # '1' qubit state as complex state vec
-        v = (v0, v1)
-
-        if _fastcalc is None:  # do it the slow way using numpy
-            vec = _functools.reduce(_np.kron, [v[i] for i in zvals])
-        else:
-            typ = complex
-            fast_kron_array = _np.ascontiguousarray(
-                _np.empty((len(zvals), factor_dim), typ))
-            fast_kron_factordims = _np.ascontiguousarray(_np.array([factor_dim] * len(zvals), _np.int64))
-            for i, zi in enumerate(zvals):
-                fast_kron_array[i, :] = v[zi]
-            vec = _np.ascontiguousarray(_np.empty(factor_dim**len(zvals), typ))
-            _fastcalc.fast_kron_complex(vec, fast_kron_array, fast_kron_factordims)
-
-        self.zvals = zvals
-        self.basis = basis
-
-        if _qibo is None: raise ValueError("qibo is not installed! Must `pip install qibo` to use the 'qibo' evotype")
-        state_space = _StateSpace.cast(state_space)
-        qibo_circuit = _qibo.models.Circuit(state_space.num_qubits, density_matrix=_get_densitymx_mode())
-        super(StateRepComputational, self).__init__(qibo_circuit, vec, state_space)
-
-
-class StateRepComposed(StateRep):
-    def __init__(self, state_rep, op_rep, state_space):
-        self.state_rep = state_rep
-        self.op_rep = op_rep
-        super(StateRepComposed, self).__init__(None, None, state_space)  # this state rep is *not* actionable
-
-    def reps_have_changed(self):
-        pass  # not needed -- don't actually hold ops
-
-    def actionable_staterep(self):
-        state_rep = self.state_rep.actionable_staterep()
-        return self.op_rep.acton(state_rep)
-
-    @property
-    def basis(self):
-        # (all qibo state reps need to have a .basis property)
-        return self.state_rep.basis
-
-#REMOVE
-#    def chp_ops(self, seed_or_state=None):
-#        return self.state_rep.chp_ops(seed_or_state=seed_or_state) \
-#            + self.op_rep.chp_ops(seed_or_state=seed_or_state)
-
-# TODO: Untested, only support computational and composed for now
-#class StateRepTensorProduct(StateRep):
-#    def __init__(self, factor_state_reps, state_space):
-#        self.factor_reps = factor_state_reps
-#        super(StateRepTensorProduct, self).__init__([], state_space)
-#        self.reps_have_changed()
-#
-#    def reps_have_changed(self):
-#        chp_ops = []
-#        current_iqubit = 0
-#        for factor in self.factor_reps:
-#            local_to_tp_index = {str(iloc): str(itp) for iloc, itp in
-#                                 enumerate(range(current_iqubit, current_iqubit + factor.num_qubits))}
-#            chp_ops.extend([_update_chp_op(op, local_to_tp_index) for op in self.chp_ops])
-#            current_iqubit += factor.num_qubits
-#        self.chp_ops = chp_ops
diff --git a/pygsti/io/__init__.py b/pygsti/io/__init__.py
index 1b76e1c56..9dea86475 100644
--- a/pygsti/io/__init__.py
+++ b/pygsti/io/__init__.py
@@ -12,8 +12,7 @@
 
 # Import the most important/useful routines of each module into
 # the package namespace
-#from .legacyio import enable_no_cython_unpickling
-#from .legacyio import enable_old_object_unpickling  # , disable_old_object_unpickling
+
 from .readers import *
 from .metadir import *
 from .stdinput import *
diff --git a/setup.py b/setup.py
index 118040267..bac69bb6e 100644
--- a/setup.py
+++ b/setup.py
@@ -79,7 +79,6 @@
         'seaborn',
         'scipy',
         'ply',
-        'qibo<=0.1.7',
         'cirq-core',
         'notebook',
         'ipython',
@@ -157,7 +156,6 @@ def setup_with_extensions(extensions=None):
             'pygsti.evotypes.stabilizer',
             'pygsti.evotypes.stabilizer_slow',
             'pygsti.evotypes.chp',
-            'pygsti.evotypes.qibo',
             'pygsti.extras',
             'pygsti.extras.rb',
             'pygsti.extras.rpe',


Test patch:
diff --git a/test/test_packages/objects/test_qibogst.py b/test/test_packages/objects/test_qibogst.py
deleted file mode 100644
index 15013da1b..000000000
--- a/test/test_packages/objects/test_qibogst.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import unittest
-from ..testutils import BaseTestCase
-
-import pygsti
-from pygsti.modelpacks import smq1Q_XYI as std
-
-#qibo is also currently suffering from numpy 1.24.0 related deprecation problems
-#that result in this dying on this import.
-try:
-    from pygsti.evotypes import qibo as evo_qibo  # don't clobber qibo!
-except (ImportError, AttributeError):
-    pass
-
-@unittest.skip("Qibo import is currently broken because of numpy 1.24, re-enable once the devs fix it.")
-class TestQiboGSTCase(BaseTestCase):
-    def setUp(self):
-        evo_qibo.densitymx_mode = True
-        evo_qibo.minimal_space = 'HilbertSchmidt'  # maybe this should be set automatically?
-
-    def _rungst_comparison(self, ptype):
-        mdl_densitymx = std.target_model(ptype, evotype='densitymx', simulator='map')
-        mdl_qibo = std.target_model(ptype, evotype='qibo', simulator='map')
-
-        edesign = std.create_gst_experiment_design(1)
-        mdl_datagen = std.target_model().depolarize(op_noise=0.05, spam_noise=0.02)
-        ds = pygsti.data.simulate_data(mdl_datagen, edesign, 1000, seed=1234)
-        data = pygsti.protocols.ProtocolData(edesign, ds)
-
-        proto = pygsti.protocols.GST(mdl_densitymx, gaugeopt_suite=None, optimizer={'maxiter': 100}, verbosity=3)
-        results_densitymx = proto.run(data)
-
-        proto = pygsti.protocols.GST(mdl_qibo, gaugeopt_suite=None, optimizer={'maxiter': 3}, verbosity=3)
-        results_qibo = proto.run(data)  # profiling this shows that all time is bound up in qibo object construction overhead
-
-        #TODO: verify that results are the approximately the same
-
-    @unittest.skip("Qibo GST is currently too slow to test")
-    def test_qibo_gst_fullCPTP(self):
-        return self._rungst_comparison('full CPTP')
-
-    @unittest.skip("Qibo GST is currently too slow to test")
-    def test_qibo_gst_1plusCPTPLND(self):
-        return self._rungst_comparison('1+(CPTPLND)')
diff --git a/test/test_packages/reportb/test_workspace.py b/test/test_packages/reportb/test_workspace.py
index 0c08b3b2b..aeffb0e25 100644
--- a/test/test_packages/reportb/test_workspace.py
+++ b/test/test_packages/reportb/test_workspace.py
@@ -312,30 +312,6 @@ def test_plot_creation(self):
         with self.assertRaises(ValueError):
             w.ColorBoxPlot(("chi2",), self.gss, self.ds, self.mdl, typ="foobar")
 
-        from pygsti.algorithms import directx as dx
-        #specs = pygsti.construction.build_spam_specs(
-        #        prepStrs=prepStrs,
-        #        effectStrs=effectStrs,
-        #        prep_labels=list(self.mdl.preps.keys()),
-        #        effect_labels=self.mdl.get_effect_labels() )
-
-        baseStrs = [plaq.base for _, plaq in self.gss.iter_plaquettes()]
-        #print(f'{baseStrs=}')
-        #print(f'{prepStrs=}')
-        #print(f'{effectStrs=}')
-        #print(self.ds)
-        #print(f'{list(self.gss)=}')
-        #print(self.mdl)
-        
-        directModels = dx.direct_mlgst_models(
-            baseStrs, self.ds, prepStrs, effectStrs, self.tgt, svd_truncate_to=4)
-        #print(f'{directModels=}')
-        plts.append( w.ColorBoxPlot(["chi2","logl","blank"], self.gss,
-                                    self.ds, self.mdl, box_labels=False, direct_gst_models=directModels) )
-        plts.append( w.ColorBoxPlot(["errorrate"], self.gss,
-                                    self.ds, self.mdl, box_labels=False, sum_up=True,
-                                    direct_gst_models=directModels) )
-
         gmx = np.identity(4,'d'); gmx[3,0] = 0.5
         plts.append(w.MatrixPlot(gmx, -1, 1, ['a','b','c','d'], ['e','f','g','h'], "X", "Y",
                                  colormap = pygsti.report.colormaps.DivergingColormap(vmin=-2, vmax=2)))
diff --git a/test/unit/algorithms/test_directx.py b/test/unit/algorithms/test_directx.py
deleted file mode 100644
index f7249af84..000000000
--- a/test/unit/algorithms/test_directx.py
+++ /dev/null
@@ -1,85 +0,0 @@
-import pygsti.circuits as pc
-import pygsti.data as pdata
-from pygsti.algorithms import directx
-from pygsti.baseobjs import Label as L
-from pygsti.circuits import Circuit
-from . import fixtures
-from ..util import BaseCase
-
-_SEED = 1234
-
-# TODO optimize!
-class DirectXTester(BaseCase):
-    @classmethod
-    def setUpClass(cls):
-        super(DirectXTester, cls).setUpClass()
-        cls._tgt = fixtures.model.copy()
-        cls.prepStrs = fixtures.prep_fids
-        cls.effectStrs = fixtures.meas_fids
-        cls.strs = [Circuit([], line_labels=(0,)),
-                    Circuit([L('Gxpi2',0)], line_labels=(0,)),
-                    Circuit([L('Gypi2',0)], line_labels=(0,)),
-                    Circuit([L('Gxpi2',0), L('Gxpi2',0)], line_labels=(0,)),
-                    Circuit([L('Gxpi2',0), L('Gypi2',0), L('Gxpi2',0)], line_labels=(0,))
-                    ]
-                    
-        expstrs = pc.create_circuits(
-            "f0+base+f1", order=['f0', 'f1', 'base'], f0=cls.prepStrs,
-            f1=cls.effectStrs, base=cls.strs
-        )
-        cls._ds = pdata.simulate_data(fixtures.datagen_gateset.copy(), expstrs, 1000, 'multinomial', seed=_SEED)
-
-    def setUp(self):
-        self.tgt = self._tgt.copy()
-        self.ds = self._ds.copy()
-
-    def test_model_with_lgst_circuit_estimates(self):
-        model = directx.model_with_lgst_circuit_estimates(
-            self.strs, self.ds, self.prepStrs, self.effectStrs, self.tgt,
-            svd_truncate_to=4, verbosity=10
-        )
-        # TODO assert correctness
-
-        model = directx.model_with_lgst_circuit_estimates(
-            self.strs, self.ds, self.prepStrs, self.effectStrs, self.tgt,
-            include_target_ops=False, svd_truncate_to=4, verbosity=10
-        )
-        # TODO assert correctness
-
-        circuit_labels = [L('G0'), L('G1'), L('G2'), L('G3'), L('G4')]
-        model = directx.model_with_lgst_circuit_estimates(
-            self.strs, self.ds, self.prepStrs, self.effectStrs, self.tgt,
-            circuit_labels=circuit_labels,
-            include_target_ops=False, svd_truncate_to=4, verbosity=10
-        )
-        self.assertEqual(
-            set(model.operations.keys()),
-            set(circuit_labels)
-        )
-
-    def test_direct_lgst_models(self):
-        gslist = directx.direct_lgst_models(
-            self.strs, self.ds, self.prepStrs, self.effectStrs, self.tgt,
-            op_label_aliases=None, svd_truncate_to=4, verbosity=10)
-        # TODO assert correctness
-
-    def test_direct_mc2gst_models(self):
-        gslist = directx.direct_mc2gst_models(
-            self.strs, self.ds, self.prepStrs, self.effectStrs, self.tgt,
-            op_label_aliases=None, min_prob_clip_for_weighting=1e-4,
-            prob_clip_interval=(-1e6, 1e6), svd_truncate_to=4, verbosity=10)
-        # TODO assert correctness
-
-    def test_direct_mlgst_models(self):
-        gslist = directx.direct_mlgst_models(
-            self.strs, self.ds, self.prepStrs, self.effectStrs, self.tgt,
-            op_label_aliases=None, min_prob_clip=1e-6, prob_clip_interval=(-1e6, 1e6),
-            svd_truncate_to=4, verbosity=10)
-        # TODO assert correctness
-
-    def test_focused_mc2gst_models(self):
-        gslist = directx.focused_mc2gst_models(
-            self.strs, self.ds, self.prepStrs, self.effectStrs, self.tgt,
-            op_label_aliases=None, min_prob_clip_for_weighting=1e-4,
-            prob_clip_interval=(-1e6, 1e6), verbosity=10)
-        # TODO assert correctness
diff --git a/test/unit/objects/test_qibo_evotype.py b/test/unit/objects/test_qibo_evotype.py
deleted file mode 100644
index 4fd798990..000000000
--- a/test/unit/objects/test_qibo_evotype.py
+++ /dev/null
@@ -1,127 +0,0 @@
-
-import unittest
-import numpy as np
-from packaging import version
-    
-from pygsti.processors import QubitProcessorSpec
-from pygsti.models import create_crosstalk_free_model
-from pygsti.circuits import Circuit
-from pygsti.modelpacks import smq2Q_XYI as std
-from pygsti.modelpacks import smq1Q_XYI as std1Q
-
-from pygsti.evotypes.densitymx_slow.opreps import OpRepIdentityPlusErrorgen
-from pygsti.evotypes.densitymx.opreps import OpRepDenseSuperop
-from ..util import BaseCase
-
-#also catch the attribute error here
-try:
-    np.int = int  # because old versions of qibo use deprecated (and now removed)
-    np.float = float  # types within numpy.  So this is a HACK to get around this.
-    np.complex = complex
-    import qibo as _qibo
-    if version.parse(_qibo.__version__) != version.parse("0.1.7"):
-        _qibo = None  # version too low - doesn't contain all the builtin gates, e.g. qibo.gates.S
-except (ImportError, AttributeError):
-    _qibo = None
-
-#Deprecated numpy calls are currently breaking the qibo import
-#so add in a catch for this exception and skip this test if that happens.
-try:
-    from pygsti.evotypes import qibo as evo_qibo  # don't clobber qibo!
-except AttributeError:
-    evo_qibo = None
-
-
-
-class QiboEvotypeTester(BaseCase):
-
-    def setUp(self):
-        self.pspec = QubitProcessorSpec(2, ['Gxpi2', 'Gypi2', 'Gcnot'], geometry='line')
-        self.test_circuit = Circuit("Gxpi2:0^2", line_labels=(0, 1))
-        # Circuit("Gxpi2:0Gypi2:1Gcnot:0:1", line_labels=(0,1))
-
-        self.mdl_densitymx = create_crosstalk_free_model(
-            self.pspec, evotype='densitymx', simulator='map',
-            depolarization_strengths={('Gxpi2',0): 0.075, ('Gypi2',0): 0.075})
-        self.probs_densitymx = self.mdl_densitymx.probabilities(self.test_circuit)
-
-    def check_probs(self, probs1, probs2, delta=1e-6):
-        for k, v in probs2.items():
-            self.assertAlmostEqual(probs1[k], v, delta=delta)
-
-    @unittest.skipIf(_qibo is None, "qibo package not installed so cannot test")
-    def test_qibo_circuitsim_statevec(self):
-        evo_qibo.densitymx_mode = False
-        evo_qibo.nshots = 1000
-        mdl_qibo = create_crosstalk_free_model(self.pspec, evotype='qibo', simulator='map',
-                                               depolarization_strengths={('Gxpi2',0): 0.075, ('Gypi2',0): 0.075})
-        probs = mdl_qibo.probabilities(self.test_circuit)
-        self.check_probs(probs, self.probs_densitymx, delta=0.04)  # loose check for 1000 shots
-
-    @unittest.skipIf(_qibo is None, "qibo package not installed so cannot test")
-    def test_qibo_circuitsim_densitymx(self):
-        evo_qibo.densitymx_mode = True
-        mdl_qibo = create_crosstalk_free_model(self.pspec, evotype='qibo', simulator='map',
-                                               depolarization_strengths={('Gxpi2',0): 0.075, ('Gypi2',0): 0.075})
-        probs = mdl_qibo.probabilities(self.test_circuit)
-        self.check_probs(probs, self.probs_densitymx, delta=1e-6)  # tight check (should be ~exact)
-
-    #Note: for FUTURE work - this doesn't work for map fwdsim like the densitymx version below
-    # because the qibo effect reps (needed for explicit models) only work for densitymx mode.  These
-    # 'matrix' simulator runs but really shouldn't (I think it uses the qibo std-basis matrices?) and
-    # gets bogus results, and we should probably at least make sure this errors appropriately.
-    #def test_qibo_stdmodel_statevec(self):
-    #    pass
-
-    @unittest.skipIf(_qibo is None, "qibo package not installed so cannot test")
-    def test_qibo_stdmodel_densitymx(self):
-        evo_qibo.densitymx_mode = True
-        mdl_std_qibo = std.target_model('static unitary', evotype='qibo', simulator='map')
-        probs = mdl_std_qibo.probabilities(self.test_circuit)
-        self.assertAlmostEqual(probs['00'], 0.0)
-        self.assertAlmostEqual(probs['01'], 0.0)
-        self.assertAlmostEqual(probs['10'], 1.0)
-        self.assertAlmostEqual(probs['11'], 0.0)
-
-    @unittest.skipIf(_qibo is None, "qibo package not installed so cannot test")
-    def test_FullCPTP_parameterization(self):  # maybe move or split this test elsewhere too?
-        evo_qibo.densitymx_mode = True
-        evo_qibo.minimal_space = 'HilbertSchmidt'  # maybe this should be set automatically?
-
-        # 'full CPTP' or test new '1+(CPTPLND)'
-        mdl_densitymx_slow = std1Q.target_model('full CPTP', evotype='densitymx_slow', simulator='map')
-        mdl_densitymx = std1Q.target_model('full CPTP', evotype='densitymx', simulator='map')
-        mdl_qibo = std1Q.target_model('full CPTP', evotype='qibo', simulator='map')
-
-        c = Circuit("Gxpi2:0", line_labels=(0,))
-        probs1 = mdl_densitymx_slow.probabilities(c)
-        probs2 = mdl_densitymx.probabilities(c)
-        probs3 = mdl_qibo.probabilities(c)
-        self.assertAlmostEqual(probs1['0'], 0.5)
-        self.assertAlmostEqual(probs1['1'], 0.5)
-        self.check_probs(probs1, probs2, delta=1e-6)
-        self.check_probs(probs1, probs3, delta=1e-6)
-
-    @unittest.skipIf(_qibo is None, "qibo package not installed so cannot test")
-    def test_1plusCPTPLND_parameterization(self):  # maybe move or split this test elsewhere too?
-        evo_qibo.densitymx_mode = True
-        evo_qibo.minimal_space = 'HilbertSchmidt'  # maybe this should be set automatically?
-
-        mdl_densitymx_slow = std1Q.target_model('1+(CPTPLND)', evotype='densitymx_slow', simulator='map')
-        mdl_densitymx = std1Q.target_model('1+(CPTPLND)', evotype='densitymx', simulator='map')
-        mdl_qibo = std1Q.target_model('1+(CPTPLND)', evotype='qibo', simulator='map')
-
-        self.assertTrue(isinstance(mdl_densitymx_slow.operations['Gxpi2', 0]._rep.factor_reps[1],
-                                   OpRepIdentityPlusErrorgen))
-        self.assertTrue(isinstance(mdl_densitymx.operations['Gxpi2', 0]._rep.factor_reps[1],
-                                   OpRepDenseSuperop))
-        # Note: we haven't mirrored OpRepIdentityPlusErrorgen in densitymx evotype
-
-        c = Circuit("Gxpi2:0", line_labels=(0,))
-        probs1 = mdl_densitymx_slow.probabilities(c)
-        probs2 = mdl_densitymx.probabilities(c)
-        probs3 = mdl_qibo.probabilities(c)
-        self.assertAlmostEqual(probs1['0'], 0.5)
-        self.assertAlmostEqual(probs1['1'], 0.5)
-        self.check_probs(probs1, probs2, delta=1e-6)
-        self.check_probs(probs1, probs3, delta=1e-6)