def test_init(self):
        """Test _core._affine._base.AffineOperator.__init__()."""
        fs, As = self._set_up_affine_attributes()

        # Try with non-callables.
        with pytest.raises(TypeError) as ex:
            roi.AffineOperator(As, As)
        assert ex.value.args[0] == \
            "coefficients of affine operator must be callable"

        # Try with different number of functions and matrices.
        with pytest.raises(ValueError) as ex:
            roi.AffineOperator(fs, As[:-1])
        assert ex.value.args[0] == \
            f"{len(fs)} = len(coeffs) != len(matrices) = {len(As[:-1])}"

        # Try with matrices of different shapes.
        with pytest.raises(ValueError) as ex:
            roi.AffineOperator(fs, As[:-1] + [np.random.random((4, 4))])
        assert ex.value.args[0] == \
            "affine component matrix shapes do not match"

        # Correct usage.
        affop = roi.AffineOperator(fs, As)
        for A in As:
            assert affop.shape == A.shape
    def _test_predict(self, ModelClass):
        """Test predict() methods for Affine classes:
        * _core._affine._inferred.AffineInferredDiscreteROM.predict()
        * _core._affine._inferred.AffineInferredContinuousROM.predict()
        * _core._affine._intrusive.AffineIntrusiveDiscreteROM.predict()
        * _core._affine._intrusive.AffineIntrusiveContinuousROM.predict()
        """
        model = ModelClass("cAHG")

        # Get test data.
        n, k, m, r = 60, 50, 20, 10
        X = _get_data(n, k, m)[0]
        Vr = la.svd(X)[0][:, :r]

        # Get test operators.
        ident = lambda a: a
        c, A, H, G, B = _get_operators(r, m)
        model.Vr = Vr
        model.c_ = roi.AffineOperator([ident, ident], [c, c])
        model.A_ = roi.AffineOperator([ident, ident, ident], [A, A, A])
        model.H_ = roi.AffineOperator([ident], [H])
        model.G_ = roi.AffineOperator([ident, ident], [G, G])
        model.B_ = None

        # Predict.
        if issubclass(ModelClass, roi._core._base._ContinuousROM):
            model.predict(1, X[:, 0], np.linspace(0, 1, 100))
        else:
            model.predict(1, X[:, 0], 100)
    def test_eq(self):
        """Test _core._affine._base.AffineOperator.__eq__()."""
        fs, As = self._set_up_affine_attributes()
        affop1 = roi.AffineOperator(fs[:-1], As[:-1])
        affop2 = roi.AffineOperator(fs, As)

        assert affop1 != 1
        assert affop1 != affop2
        affop1 = roi.AffineOperator(fs, As)
        assert affop1 == affop2
    def test_call(self):
        """Test _core._affine._base.AffineOperator.__call__()."""
        fs, As = self._set_up_affine_attributes()

        # Try without matrices set.
        affop = roi.AffineOperator(fs, As)
        Ap = affop(10)
        assert Ap.shape == (5, 5)
        assert np.allclose(Ap, np.sin(10)*As[0] + \
                               np.cos(10)*As[1] + np.exp(10)*As[2])
    def test_init(self):
        """Test _core._affine._base.AffineOperator.__init__()."""
        fs, As = self._set_up_affine_attributes()

        # Try with different number of functions and matrices.
        with pytest.raises(ValueError) as ex:
            roi.AffineOperator(fs, As[:-1])
        assert ex.value.args[0] == "expected 3 matrices, got 2"

        # Try with matrices of different shapes.
        with pytest.raises(ValueError) as ex:
            roi.AffineOperator(fs, As[:-1] + [np.random.random((4, 4))])
        assert ex.value.args[0] == \
            "affine operator matrix shapes do not match ((4, 4) != (5, 5))"

        # Correct usage.
        affop = roi.AffineOperator(fs, As)
        affop = roi.AffineOperator(fs)
        affop.matrices = As
    def test_validate_coeffs(self):
        """Test _core._affine._base.AffineOperator.validate_coeffs()."""
        fs, As = self._set_up_affine_attributes()

        # Try with non-callables.
        affop = roi.AffineOperator(As)
        with pytest.raises(ValueError) as ex:
            affop.validate_coeffs(10)
        assert ex.value.args[0] == \
            "coefficients of affine operator must be callable functions"

        # Try with vector-valued functions.
        f1 = lambda t: np.array([t, t**2])
        affop = roi.AffineOperator([f1, f1])
        with pytest.raises(ValueError) as ex:
            affop.validate_coeffs(10)
        assert ex.value.args[0] == \
            "coefficient functions of affine operator must return a scalar"

        # Correct usage.
        affop = roi.AffineOperator(fs, As)
        affop.validate_coeffs(0)
    def test_call(self):
        """Test _core._affine._base.AffineOperator.__call__()."""
        fs, As = self._set_up_affine_attributes()

        # Try without matrices set.
        affop = roi.AffineOperator(fs)
        with pytest.raises(RuntimeError) as ex:
            affop(10)
        assert ex.value.args[0] == "component matrices not initialized!"

        # Correct usage.
        affop.matrices = As
        Ap = affop(10)
        assert Ap.shape == (5, 5)
        assert np.allclose(Ap, np.sin(10)*As[0] + \
                               np.cos(10)*As[1] + np.exp(10)*As[2])