Beispiel #1
0
    def test_adc1_linear_solve(self):
        conv_tol = 1e-9
        matrix = adcc.AdcMatrix("adc1", cache.refstate["h2o_sto3g"])
        rhs = adcc.guess_zero(matrix)
        rhs["s"].set_random()

        guess = rhs.copy()
        guess["s"].set_random()
        res = conjugate_gradient(matrix,
                                 rhs,
                                 guess,
                                 callback=cgprint,
                                 conv_tol=conv_tol)
        residual = matrix @ res.solution - rhs
        assert np.sqrt(residual @ residual) < conv_tol
Beispiel #2
0
 def test_functionality(self):
     ground_state = adcc.LazyMp(cache.refstate["h2o_sto3g"])
     matrix = adcc.AdcMatrix("adc2", ground_state)
     vectors = [adcc.guess_zero(matrix) for i in range(2)]
     for vec in vectors:
         vec.set_random()
     v, w = vectors
     with pytest.raises(AttributeError):
         v.pph
     with pytest.raises(AttributeError):
         v.pph = w.ph
     # setattr with expression
     z = adcc.zeros_like(v)
     z.ph = v.ph + w.ph
     z -= w
     np.testing.assert_allclose(v.ph.to_ndarray(), z.ph.to_ndarray())
Beispiel #3
0
    def template_matmul(self, case):
        shift = -0.3
        matrix, shifted = self.construct_matrices(case, shift)

        vec = adcc.guess_zero(matrix)
        vec.set_random()

        ores = matrix @ vec
        sres = shifted @ vec

        assert ores.ph.describe_symmetry() == sres.ph.describe_symmetry()
        assert ores.pphh.describe_symmetry() == sres.pphh.describe_symmetry()

        diff_s = sres.ph - ores.ph - shift * vec.ph
        diff_d = sres.pphh - ores.pphh - shift * vec.pphh
        assert np.max(np.abs(diff_s.to_ndarray())) < 1e-12
        assert np.max(np.abs(diff_d.to_ndarray())) < 1e-12
Beispiel #4
0
    def template_singles_view(self, method):
        if "cvs" in method:
            reference_state = cache.refstate_cvs["h2o_sto3g"]
            shape = (8, 8)
            spaces_s = ["o2", "v1"]
        else:
            reference_state = cache.refstate["h2o_sto3g"]
            shape = (40, 40)
            spaces_s = ["o1", "v1"]
        matrix = adcc.AdcMatrix(method, adcc.LazyMp(reference_state))
        view = adcc.AdcBlockView(matrix, "s")

        assert view.ndim == 2
        assert view.is_core_valence_separated == ("cvs" in method)
        assert view.shape == shape
        assert len(view) == shape[0]

        assert view.blocks == ["s"]
        assert view.has_block("s")
        assert not view.has_block("d")
        assert not view.has_block("t")
        assert view.block_spaces("s") == spaces_s

        assert view.reference_state == reference_state
        assert view.mospaces == reference_state.mospaces
        assert isinstance(view.timer, adcc.timings.Timer)
        assert view.to_cpp() == matrix.to_cpp()

        # Check diagonal
        diff = matrix.diagonal("s") - view.diagonal("s")
        assert diff.dot(diff) < 1e-12

        # Check @ (one vector and multiple vectors)
        invec = adcc.guess_zero(matrix)
        invec["s"].set_random()
        # "d" left as zero
        invec_singles = adcc.AmplitudeVector(invec["s"])

        ref = matrix @ invec
        res = view @ invec_singles
        diff = res["s"] - ref["s"]
        assert diff.dot(diff) < 1e-12

        res = view @ [invec_singles, invec_singles, invec_singles]
        diff = [res[i]["s"] - ref["s"] for i in range(3)]
        assert max(d.dot(d) for d in diff) < 1e-12
Beispiel #5
0
    def template_singles_view(self, method):
        if "cvs" in method:
            reference_state = cache.refstate_cvs["h2o_sto3g"]
            shape = (8, 8)
            spaces_ph = ["o2", "v1"]
        else:
            reference_state = cache.refstate["h2o_sto3g"]
            shape = (40, 40)
            spaces_ph = ["o1", "v1"]
        matrix = adcc.AdcMatrix(method, adcc.LazyMp(reference_state))
        view = matrix.block_view("ph_ph")

        assert view.ndim == 2
        assert view.is_core_valence_separated == ("cvs" in method)
        assert view.shape == shape
        assert len(view) == shape[0]

        assert view.axis_blocks == ["ph"]
        assert sorted(view.axis_spaces.keys()) == view.axis_blocks
        assert sorted(view.axis_lengths.keys()) == view.axis_blocks
        assert view.axis_spaces["ph"] == spaces_ph
        assert view.axis_lengths["ph"] == shape[0]

        assert view.reference_state == reference_state
        assert view.mospaces == reference_state.mospaces
        assert isinstance(view.timer, adcc.timings.Timer)

        # Check diagonal
        diff = matrix.diagonal().ph - view.diagonal().ph
        assert diff.dot(diff) < 1e-12

        # Check @ (one vector and multiple vectors)
        invec = adcc.guess_zero(matrix)
        invec.ph.set_random()
        # "d" left as zero
        invec_singles = adcc.AmplitudeVector(ph=invec.ph)

        ref = matrix @ invec
        res = view @ invec_singles
        diff = res.ph - ref.ph
        assert diff.dot(diff) < 1e-12

        res = view @ [invec_singles, invec_singles, invec_singles]
        diff = [res[i].ph - ref.ph for i in range(3)]
        assert max(d.dot(d) for d in diff) < 1e-12
Beispiel #6
0
    def test_matvec_adc2(self):
        ground_state = adcc.LazyMp(cache.refstate["h2o_sto3g"])
        matrix = adcc.AdcMatrix("adc2", ground_state)

        vectors = [adcc.guess_zero(matrix) for i in range(3)]
        for vec in vectors:
            vec.set_random()
        v, w, x = vectors

        # Compute references:
        refv = matrix.matvec(v)
        refw = matrix.matvec(w)
        refx = matrix.matvec(x)

        # @ operator (1 vector)
        resv = matrix @ v
        diffv = refv - resv
        assert diffv.ph.dot(diffv.ph) < 1e-12
        assert diffv.pphh.dot(diffv.pphh) < 1e-12

        # @ operator (multiple vectors)
        resv, resw, resx = matrix @ [v, w, x]
        diffs = [refv - resv, refw - resw, refx - resx]
        for i in range(3):
            assert diffs[i].ph.dot(diffs[i].ph) < 1e-12
            assert diffs[i].pphh.dot(diffs[i].pphh) < 1e-12

        # compute matvec
        resv = matrix.matvec(v)
        diffv = refv - resv
        assert diffv.ph.dot(diffv.ph) < 1e-12
        assert diffv.pphh.dot(diffv.pphh) < 1e-12

        resv = matrix.rmatvec(v)
        diffv = refv - resv
        assert diffv.ph.dot(diffv.ph) < 1e-12
        assert diffv.pphh.dot(diffv.pphh) < 1e-12

        # Test apply
        resv.ph = matrix.block_apply("ph_ph", v.ph)
        resv.ph += matrix.block_apply("ph_pphh", v.pphh)
        refv = matrix.matvec(v)
        diffv = resv.ph - refv.ph
        assert diffv.dot(diffv) < 1e-12
Beispiel #7
0
    def test_matvec_adc2(self):
        ground_state = adcc.LazyMp(cache.refstate["h2o_sto3g"])
        matrix = adcc.AdcMatrix("adc2", ground_state)
        cppmatrix = libadcc.AdcMatrix("adc2", ground_state)

        vectors = [adcc.guess_zero(matrix) for i in range(3)]
        for vec in vectors:
            vec["s"].set_random()
            vec["d"].set_random()
        v, w, x = vectors

        # Compute references:
        refv = adcc.empty_like(v)
        refw = adcc.empty_like(w)
        refx = adcc.empty_like(x)
        cppmatrix.compute_matvec(v.to_cpp(), refv.to_cpp())
        cppmatrix.compute_matvec(w.to_cpp(), refw.to_cpp())
        cppmatrix.compute_matvec(x.to_cpp(), refx.to_cpp())

        # @ operator (1 vector)
        resv = matrix @ v
        diffv = refv - resv
        assert diffv["s"].dot(diffv["s"]) < 1e-12
        assert diffv["d"].dot(diffv["d"]) < 1e-12

        # @ operator (multiple vectors)
        resv, resw, resx = matrix @ [v, w, x]
        diffs = [refv - resv, refw - resw, refx - resx]
        for i in range(3):
            assert diffs[i]["s"].dot(diffs[i]["s"]) < 1e-12
            assert diffs[i]["d"].dot(diffs[i]["d"]) < 1e-12

        # compute matvec
        matrix.compute_matvec(v, resv)
        diffv = refv - resv
        assert diffv["s"].dot(diffv["s"]) < 1e-12
        assert diffv["d"].dot(diffv["d"]) < 1e-12

        matrix.compute_apply("ss", v["s"], resv["s"])
        cppmatrix.compute_apply("ss", v["s"], refv["s"])
        diffv = resv["s"] - refv["s"]
        assert diffv.dot(diffv) < 1e-12
Beispiel #8
0
def make_mock_adc_state(refstate, matmethod, kind, reference):
    ground_state = LazyMp(refstate, CacheAllPolicy())
    matrix = AdcMatrix(matmethod, ground_state)

    # Number of full state results
    n_full = len(reference[kind]["eigenvectors_singles"])

    state = AdcMockState(matrix)
    state.method = matrix.method
    state.ground_state = ground_state
    state.reference_state = refstate
    state.kind = kind
    state.eigenvalues = reference[kind]["eigenvalues"][:n_full]

    spin_change = 0
    if refstate.restricted and kind == "singlet":
        symm = "symmetric"
    elif refstate.restricted and kind == "triplet":
        symm = "antisymmetric"
    elif kind in ["state", "spin_flip"]:
        symm = "none"
    else:
        raise ValueError("Unknown kind: {}".format(kind))

    state.eigenvectors = [
        guess_zero(matrix,
                   irrep="A",
                   spin_change=spin_change,
                   spin_block_symmetrisation=symm) for i in range(n_full)
    ]

    has_doubles = "eigenvectors_doubles" in reference[kind]
    vec_singles = reference[kind]["eigenvectors_singles"]
    vec_doubles = reference[kind].get("eigenvectors_doubles", None)
    for i, evec in enumerate(state.eigenvectors):
        evec["s"].set_from_ndarray(vec_singles[i])
        if has_doubles:
            evec["d"].set_from_ndarray(vec_doubles[i], 1e-14)
    return ExcitedStates(state)
Beispiel #9
0
    def to_ndarray(self, out=None):
        """
        Return the ADC matrix object as a dense numpy array. Converts the sparse
        internal representation of the ADC matrix to a dense matrix and return
        as a numpy array.

        Notes
        -----

        This method is only intended to be used for debugging and
        visualisation purposes as it involves computing a large amount of
        matrix-vector products and the returned array consumes a considerable
        amount of memory.

        The resulting matrix has no spin symmetry imposed, which means that
        its eigenspectrum may contain non-physical excitations (e.g. with linear
        combinations of α->β and α->α components in the excitation vector).

        This function has not been sufficiently tested to be considered stable.
        """
        # TODO Update to ph / pphh
        # TODO Still uses deprecated functions
        import tqdm

        from adcc import guess_zero

        # Get zero amplitude of the appropriate symmetry
        # (TODO: Only true for C1, where there is only a single irrep)
        ampl_zero = guess_zero(self)
        assert self.mospaces.point_group == "C1"

        # Build the shape of the returned array
        # Since the basis of the doubles block is not the unit vectors
        # this *not* equal to the shape of the AdcMatrix object
        basis = {b: self.dense_basis(b) for b in self.axis_blocks}
        mat_len = sum(len(basis[b]) for b in basis)

        if out is None:
            out = np.zeros((mat_len, mat_len))
        else:
            if out.shape != (mat_len, mat_len):
                raise ValueError("Output array has shape ({0:}, {1:}), but "
                                 "shape ({2:}, {2:}) is required."
                                 "".format(*out.shape, mat_len))
            out[:] = 0  # Zero all data in out.

        # Check for the cases actually implemented
        if any(b not in ("ph", "pphh") for b in self.axis_blocks):
            raise NotImplementedError("Blocks other than ph and pphh "
                                      "not implemented")
        if "ph" not in self.axis_blocks:
            raise NotImplementedError("Block 'ph' needs to be present")

        # Extract singles-singles block (contiguous)
        assert "ph" in self.axis_blocks
        n_orbs_ph = [self.mospaces.n_orbs(sp) for sp in self.axis_spaces["ph"]]
        n_ph = np.prod(n_orbs_ph)
        assert len(basis["ph"]) == n_ph
        view_ss = out[:n_ph, :n_ph].reshape(*n_orbs_ph, *n_orbs_ph)
        for i in range(n_orbs_ph[0]):
            for a in range(n_orbs_ph[1]):
                ampl = ampl_zero.copy()
                ampl.ph[i, a] = 1
                view_ss[:, :, i, a] = (self @ ampl).ph.to_ndarray()

        # Extract singles-doubles and doubles-doubles block
        if "pphh" in self.axis_blocks:
            assert self.axis_blocks == ["ph", "pphh"]
            view_sd = out[:n_ph, n_ph:].reshape(*n_orbs_ph, len(basis["pphh"]))
            view_dd = out[n_ph:, n_ph:]
            for j, bas1 in tqdm.tqdm(enumerate(basis["pphh"]),
                                     total=len(basis["pphh"])):
                ampl = ampl_zero.copy()
                for idx, val in bas1:
                    ampl.pphh[idx] = val
                ret_ampl = self @ ampl
                view_sd[:, :, j] = ret_ampl.ph.to_ndarray()

                for i, bas2 in enumerate(basis["pphh"]):
                    view_dd[i, j] = sum(val * ret_ampl.pphh[idx]
                                        for idx, val in bas2)

            out[n_ph:, :n_ph] = np.transpose(out[:n_ph, n_ph:])
        return out
Beispiel #10
0
 def guess_random(matrix, n_guesses):
     guess = adcc.guess_zero(matrix,
                             spin_block_symmetrisation="antisymmetric")
     guess["s"].set_random()
     guess["d"].set_random()
     return [guess]
Beispiel #11
0
    def test_extra_term(self):
        ground_state = adcc.LazyMp(cache.refstate["h2o_sto3g"])
        matrix_adc1 = adcc.AdcMatrix("adc1", ground_state)
        with pytest.raises(TypeError):
            matrix_adc1 += 42
        matrix = adcc.AdcMatrix("adc2", ground_state)

        with pytest.raises(TypeError):
            adcc.AdcMatrix("adc2", ground_state, diagonal_precomputed=42)
        with pytest.raises(ValueError):
            adcc.AdcMatrix("adc2",
                           ground_state,
                           diagonal_precomputed=matrix.diagonal() + 42)
        with pytest.raises(TypeError):
            AdcExtraTerm(matrix, "fail")
        with pytest.raises(TypeError):
            AdcExtraTerm(matrix, {"fail": "not_callable"})

        shift = -0.3
        shifted = AdcMatrixShifted(matrix, shift)
        # TODO: need to use AmplitudeVector to differentiate between
        # diagonals for ph and pphh
        # if we just pass numbers, i.e., shift
        # we get 2*shift on the diagonal
        ones = matrix.diagonal().ones_like()

        def __shift_ph(hf, mp, intermediates):
            def apply(invec):
                return adcc.AmplitudeVector(ph=shift * invec.ph)

            diag = adcc.AmplitudeVector(ph=shift * ones.ph)
            return AdcBlock(apply, diag)

        def __shift_pphh(hf, mp, intermediates):
            def apply(invec):
                return adcc.AmplitudeVector(pphh=shift * invec.pphh)

            diag = adcc.AmplitudeVector(pphh=shift * ones.pphh)
            return AdcBlock(apply, diag)

        extra = AdcExtraTerm(matrix, {
            'ph_ph': __shift_ph,
            'pphh_pphh': __shift_pphh
        })
        # cannot add to 'pphh_pphh' in ADC(1) matrix
        with pytest.raises(ValueError):
            matrix_adc1 += extra

        shifted_2 = matrix + extra
        shifted_3 = extra + matrix
        for manual in [shifted_2, shifted_3]:
            assert_allclose(shifted.diagonal().ph.to_ndarray(),
                            manual.diagonal().ph.to_ndarray(),
                            atol=1e-12)
            assert_allclose(shifted.diagonal().pphh.to_ndarray(),
                            manual.diagonal().pphh.to_ndarray(),
                            atol=1e-12)
            vec = adcc.guess_zero(matrix)
            vec.set_random()
            ref = shifted @ vec
            ret = manual @ vec
            diff_s = ref.ph - ret.ph
            diff_d = ref.pphh - ret.pphh
            assert np.max(np.abs(diff_s.to_ndarray())) < 1e-12
            assert np.max(np.abs(diff_d.to_ndarray())) < 1e-12