        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestAOBasisCreate failed')

        # Bind the lifetime of persistent_workspace to this object
        self.persistent_workspace = persistent_workspace

        self.initialized = True

    def __del__(self):

        if not self.initialized: return

        status = ce.cuestAOBasisDestroy(
            handle=self.ao_basis_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestAOBasisDestroy failed')

    @property
    def is_pure(self):
        query = ce.data_int32_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_IS_PURE,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return bool(query.value)

    @property
    def is_cart(self):
        query = ce.data_int32_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_IS_CART,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return bool(query.value)

    @property
    def is_mixed(self):


            raise RuntimeError('cuestAOBasisDestroy failed')

    @property
    def is_pure(self):
        query = ce.data_int32_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_IS_PURE,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return bool(query.value)

    @property
    def is_cart(self):
        query = ce.data_int32_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_IS_CART,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return bool(query.value)

    @property
    def is_mixed(self):
        query = ce.data_int32_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_IS_MIXED,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return bool(query.value)

    @property
    def natom(self):


        return bool(query.value)

    @property
    def is_cart(self):
        query = ce.data_int32_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_IS_CART,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return bool(query.value)

    @property
    def is_mixed(self):
        query = ce.data_int32_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_IS_MIXED,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return bool(query.value)

    @property
    def natom(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_NUM_ATOM,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    @property
    def nshell(self):


natom

        return bool(query.value)

    @property
    def is_mixed(self):
        query = ce.data_int32_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_IS_MIXED,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return bool(query.value)

    @property
    def natom(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_NUM_ATOM,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    @property
    def nshell(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_NUM_SHELL,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    @property
    def nao(self):


nshell

        return bool(query.value)

    @property
    def natom(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_NUM_ATOM,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    @property
    def nshell(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_NUM_SHELL,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    @property
    def nao(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_NUM_AO,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    @property
    def ncart(self):


nao

        return int(query.value)

    @property
    def nshell(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_NUM_SHELL,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    @property
    def nao(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_NUM_AO,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    @property
    def ncart(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_NUM_CART,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    @property
    def nprimitive(self):


ncart

        return int(query.value)

    @property
    def nao(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_NUM_AO,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    @property
    def ncart(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_NUM_CART,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    @property
    def nprimitive(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_NUM_PRIMITIVE,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    @property
    def max_L(self):


nprimitive

        return int(query.value)

    @property
    def ncart(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_NUM_CART,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    @property
    def nprimitive(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_NUM_PRIMITIVE,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    @property
    def max_L(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_MAX_L,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    def __str__(self):
        s = ''


        return int(query.value)

    @property
    def nprimitive(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_NUM_PRIMITIVE,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    @property
    def max_L(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_MAX_L,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    def __str__(self):
        s = ''
        s += 'CuestAOBasis:\n'
        s += '%-10s = %6d\n' % ('natom', self.natom)
        s += '%-10s = %6d\n' % ('nshell', self.nshell)
        s += '%-10s = %6d\n' % ('nao', self.nao)
        s += '%-10s = %6d\n' % ('ncart', self.ncart)
        s += '%-10s = %6d\n' % ('nprimitive', self.nprimitive)
        s += '%-10s = %6d\n' % ('max_L', self.max_L)
        s += '%-10s = %6s\n' % ('is_pure', self.is_pure)
        s += '%-10s = %6s\n' % ('is_cart', self.is_cart)
        s += '%-10s = %6s\n' % ('is_mixed', self.is_mixed)
        return s


        return int(query.value)

    @property
    def max_L(self):
        query = ce.data_uint64_t()

        status = ce.cuestQuery(
            handle=self.handle.handle,
            type=ce.CuestType.CUEST_AOBASIS,
            object=self.ao_basis_handle,
            attribute=ce.CuestAOBasisAttributes.CUEST_AOBASIS_MAX_L,
            attributeValue=query,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuest query failed')

        return int(query.value)

    def __str__(self):
        s = ''
        s += 'CuestAOBasis:\n'
        s += '%-10s = %6d\n' % ('natom', self.natom)
        s += '%-10s = %6d\n' % ('nshell', self.nshell)
        s += '%-10s = %6d\n' % ('nao', self.nao)
        s += '%-10s = %6d\n' % ('ncart', self.ncart)
        s += '%-10s = %6d\n' % ('nprimitive', self.nprimitive)
        s += '%-10s = %6d\n' % ('max_L', self.max_L)
        s += '%-10s = %6s\n' % ('is_pure', self.is_pure)
        s += '%-10s = %6s\n' % ('is_cart', self.is_cart)
        s += '%-10s = %6s\n' % ('is_mixed', self.is_mixed)
        return s


# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# 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
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import numpy as np
import atexit

import nvmath.bindings.cublas as cublas
import nvmath.bindings.cusolverDn as cusolver
import nvmath.bindings.cusolver as cusolver_base
from .gpu_matrix import GPUMatrix

# these handles are module-scoped, making them singletons
cublas_handle = cublas.create()
# Read scalar parameters like alpha and beta from CPU RAM
cublas.set_pointer_mode(
    cublas_handle,
    cublas.PointerMode.HOST
    )
cusolver_handle = cusolver.create()

def _delete_handles():
    global cublas_handle, cusolver_handle
    cublas.destroy(cublas_handle)
    cusolver.destroy(cusolver_handle)

atexit.register(_delete_handles)

class GPUMatrixUtility(object):

    @staticmethod
    def matrix_multiply(
        *,
        mat1,
        mat2,
        transpose1,
        transpose2,
        scale=1.0,
        ):

        alpha = np.array(
            scale,
            dtype=np.double,
            )
        beta = np.array(
            0.0,
            dtype=np.double,
            )
        m = mat1.ncols if transpose1 else mat1.nrows
        n = mat2.nrows if transpose2 else mat2.ncols
        k1 = mat1.nrows if transpose1 else mat1.ncols
        k2 = mat2.ncols if transpose2 else mat2.nrows
        assert k1 == k2

        c = GPUMatrix(
            nrows=m,
            ncols=n,
            )

        cublas.dgemm(
            handle=cublas_handle,
            transa=cublas.Operation.T if transpose2 else cublas.Operation.N,
            transb=cublas.Operation.T if transpose1 else cublas.Operation.N,
            m=n,
            n=m,
            k=k1,
            alpha=alpha.ctypes.data,
            a=mat2.pointer,
            lda=mat2.ncols,
            b=mat1.pointer,
            ldb=mat1.ncols,
            beta=beta.ctypes.data,
            c=c.pointer,
            ldc=c.ncols,
            )

        return c

    @staticmethod
    def ddot(
        *,
        x,
        y,
        ):

        result = np.empty(1, dtype=np.double)

        cublas.ddot(
            handle = cublas_handle,
            n=x.size,
            x=x.pointer,
            incx=1,
            y=y.pointer,
            incy=1,
            result=result.ctypes.data,
            )
        return result[0]

    @staticmethod
    def dgeam(
        *,
        transpose1,
        alpha,
        mat1,
        transpose2,
        beta,
        mat2,
        ):

        assert mat1.nrows == mat1.ncols
        assert mat2.nrows == mat2.ncols
        assert mat1.nrows == mat2.nrows

        C = mat1.clone()

        alpha=np.array(
            alpha,
            dtype=np.double,
            )
        beta=np.array(
            beta,
            dtype=np.double,
            )

        cublas.dgeam(
            handle=cublas_handle,
            transa=cublas.Operation.T if transpose1 else cublas.Operation.N,
            transb=cublas.Operation.T if transpose2 else cublas.Operation.N,
            m=mat1.nrows,
            n=mat2.ncols,
            alpha=alpha.ctypes.data,
            a=mat1.pointer,
            lda=mat1.ncols,
            beta=beta.ctypes.data,
            b=mat2.pointer,
            ldb=mat2.ncols,
            c=C.pointer,
            ldc=C.ncols,
            )

        return C

    @staticmethod
    def daxpy(
        *,
        alpha,
        x,
        y,
        ):

        alpha=np.array(
            alpha,
            dtype=np.double,
            )

        cublas.daxpy(
            handle=cublas_handle,
            n=x.size,
            alpha=alpha.ctypes.data,
            x=x.pointer,
            incx=1,
            y=y.pointer,
            incy=1,
            )

    @staticmethod
    def scale(
        *,
        matrix,
        scale,
        ):

        alpha=np.array(
            scale,
            dtype=np.double,
            )
        cublas.dscal(
            handle=cublas_handle,
            n=matrix.size,
            alpha=alpha.ctypes.data,
            x=matrix.pointer,
            incx=1,
            )

    @staticmethod
    def eigh(
        *,
        matrix
        ):

        jobz = cusolver_base.EigMode.VECTOR
        uplo = cublas.FillMode.LOWER

        assert matrix.nrows == matrix.ncols

        evecs = matrix.clone()
        evals = GPUMatrix(
            nrows=matrix.nrows,
            ncols=1,
            dtype=matrix.dtype,
            initialize=False,
            )

        d_info = GPUMatrix(
            nrows=1,
            ncols=1,
            dtype=np.int64,
            )

        # Workspace query
        lwork = np.empty(
            1,
            dtype=np.int64
            )
        lwork = cusolver.dsyevd_buffer_size(
            handle=cusolver_handle,
            jobz=jobz,
            uplo=uplo,
            n=evecs.ncols,
            a=evecs.pointer,
            lda=evecs.ncols,
            w=evals.pointer,
        )

        d_work = GPUMatrix(
            nrows=lwork,
            ncols=1,
            dtype=np.double,
            )

        # Compute eigenvalues/eigenvectors in-place
        cusolver.dsyevd(
            handle=cusolver_handle,
            jobz=jobz,
            uplo=uplo,
            n=evecs.ncols,
            a=evecs.pointer,
            lda=evecs.ncols,
            w=evals.pointer,
            work=d_work.pointer,
            lwork=lwork,
            info=d_info.pointer,
        )

        info_host = d_info.to_numpy()
        if info_host[0, 0] != 0:
            raise RuntimeError(f"dsyevd failed with info = {info_host[0, 0]}")

        evecs = GPUMatrixUtility.dgeam(
            transpose1=True,
            alpha=1.0,
            mat1=evecs,
            transpose2=False,
            beta=0.0,
            mat2=evecs,
            )

        return evals, evecs


# See the License for the specific language governing permissions and
# limitations under the License.

import numpy as np
import atexit

import nvmath.bindings.cublas as cublas
import nvmath.bindings.cusolverDn as cusolver
import nvmath.bindings.cusolver as cusolver_base
from .gpu_matrix import GPUMatrix

# these handles are module-scoped, making them singletons
cublas_handle = cublas.create()
# Read scalar parameters like alpha and beta from CPU RAM
cublas.set_pointer_mode(
    cublas_handle,
    cublas.PointerMode.HOST
    )
cusolver_handle = cusolver.create()

def _delete_handles():
    global cublas_handle, cusolver_handle
    cublas.destroy(cublas_handle)
    cusolver.destroy(cusolver_handle)

atexit.register(_delete_handles)

class GPUMatrixUtility(object):

    @staticmethod
    def matrix_multiply(
        *,
        mat1,
        mat2,
        transpose1,
        transpose2,
        scale=1.0,
        ):

        alpha = np.array(
            scale,
            dtype=np.double,
            )
        beta = np.array(


GPUMatrixUtility

import nvmath.bindings.cusolverDn as cusolver
import nvmath.bindings.cusolver as cusolver_base
from .gpu_matrix import GPUMatrix

# these handles are module-scoped, making them singletons
cublas_handle = cublas.create()
# Read scalar parameters like alpha and beta from CPU RAM
cublas.set_pointer_mode(
    cublas_handle,
    cublas.PointerMode.HOST
    )
cusolver_handle = cusolver.create()

def _delete_handles():
    global cublas_handle, cusolver_handle
    cublas.destroy(cublas_handle)
    cusolver.destroy(cusolver_handle)

atexit.register(_delete_handles)

class GPUMatrixUtility(object):

    @staticmethod
    def matrix_multiply(
        *,
        mat1,
        mat2,
        transpose1,
        transpose2,
        scale=1.0,
        ):

        alpha = np.array(
            scale,
            dtype=np.double,
            )
        beta = np.array(
            0.0,
            dtype=np.double,
            )
        m = mat1.ncols if transpose1 else mat1.nrows
        n = mat2.nrows if transpose2 else mat2.ncols
        k1 = mat1.nrows if transpose1 else mat1.ncols
        k2 = mat2.ncols if transpose2 else mat2.nrows
        assert k1 == k2

        c = GPUMatrix(
            nrows=m,
            ncols=n,
            )

        cublas.dgemm(
            handle=cublas_handle,
            transa=cublas.Operation.T if transpose2 else cublas.Operation.N,
            transb=cublas.Operation.T if transpose1 else cublas.Operation.N,
            m=n,
            n=m,
            k=k1,
            alpha=alpha.ctypes.data,
            a=mat2.pointer,
            lda=mat2.ncols,
            b=mat1.pointer,
            ldb=mat1.ncols,
            beta=beta.ctypes.data,
            c=c.pointer,
            ldc=c.ncols,
            )

        return c

    @staticmethod
    def ddot(
        *,
        x,
        y,
        ):

        result = np.empty(1, dtype=np.double)

        cublas.ddot(
            handle = cublas_handle,
            n=x.size,
            x=x.pointer,
            incx=1,
            y=y.pointer,
            incy=1,
            result=result.ctypes.data,
            )
        return result[0]

    @staticmethod
    def dgeam(
        *,
        transpose1,
        alpha,
        mat1,
        transpose2,
        beta,
        mat2,
        ):

        assert mat1.nrows == mat1.ncols
        assert mat2.nrows == mat2.ncols
        assert mat1.nrows == mat2.nrows

        C = mat1.clone()

        alpha=np.array(
            alpha,
            dtype=np.double,
            )
        beta=np.array(
            beta,
            dtype=np.double,
            )

        cublas.dgeam(
            handle=cublas_handle,
            transa=cublas.Operation.T if transpose1 else cublas.Operation.N,
            transb=cublas.Operation.T if transpose2 else cublas.Operation.N,
            m=mat1.nrows,
            n=mat2.ncols,
            alpha=alpha.ctypes.data,
            a=mat1.pointer,
            lda=mat1.ncols,
            beta=beta.ctypes.data,
            b=mat2.pointer,
            ldb=mat2.ncols,
            c=C.pointer,
            ldc=C.ncols,
            )

        return C

    @staticmethod
    def daxpy(
        *,
        alpha,
        x,
        y,
        ):

        alpha=np.array(
            alpha,
            dtype=np.double,
            )

        cublas.daxpy(
            handle=cublas_handle,
            n=x.size,
            alpha=alpha.ctypes.data,
            x=x.pointer,
            incx=1,
            y=y.pointer,
            incy=1,
            )

    @staticmethod
    def scale(
        *,
        matrix,
        scale,
        ):

        alpha=np.array(
            scale,
            dtype=np.double,
            )
        cublas.dscal(
            handle=cublas_handle,
            n=matrix.size,
            alpha=alpha.ctypes.data,
            x=matrix.pointer,
            incx=1,
            )

    @staticmethod
    def eigh(
        *,
        matrix
        ):

        jobz = cusolver_base.EigMode.VECTOR
        uplo = cublas.FillMode.LOWER

        assert matrix.nrows == matrix.ncols

        evecs = matrix.clone()
        evals = GPUMatrix(
            nrows=matrix.nrows,
            ncols=1,
            dtype=matrix.dtype,
            initialize=False,
            )

        d_info = GPUMatrix(
            nrows=1,
            ncols=1,
            dtype=np.int64,
            )

        # Workspace query
        lwork = np.empty(
            1,
            dtype=np.int64
            )
        lwork = cusolver.dsyevd_buffer_size(
            handle=cusolver_handle,
            jobz=jobz,
            uplo=uplo,
            n=evecs.ncols,
            a=evecs.pointer,
            lda=evecs.ncols,
            w=evals.pointer,
        )

        d_work = GPUMatrix(
            nrows=lwork,
            ncols=1,
            dtype=np.double,
            )

        # Compute eigenvalues/eigenvectors in-place
        cusolver.dsyevd(
            handle=cusolver_handle,
            jobz=jobz,
            uplo=uplo,
            n=evecs.ncols,
            a=evecs.pointer,
            lda=evecs.ncols,
            w=evals.pointer,
            work=d_work.pointer,
            lwork=lwork,
            info=d_info.pointer,
        )

        info_host = d_info.to_numpy()
        if info_host[0, 0] != 0:
            raise RuntimeError(f"dsyevd failed with info = {info_host[0, 0]}")

        evecs = GPUMatrixUtility.dgeam(
            transpose1=True,
            alpha=1.0,
            mat1=evecs,
            transpose2=False,
            beta=0.0,
            mat2=evecs,
            )

        return evals, evecs


# these handles are module-scoped, making them singletons
cublas_handle = cublas.create()
# Read scalar parameters like alpha and beta from CPU RAM
cublas.set_pointer_mode(
    cublas_handle,
    cublas.PointerMode.HOST
    )
cusolver_handle = cusolver.create()

def _delete_handles():
    global cublas_handle, cusolver_handle
    cublas.destroy(cublas_handle)
    cusolver.destroy(cusolver_handle)

atexit.register(_delete_handles)

class GPUMatrixUtility(object):

    @staticmethod
    def matrix_multiply(
        *,
        mat1,
        mat2,
        transpose1,
        transpose2,
        scale=1.0,
        ):

        alpha = np.array(
            scale,
            dtype=np.double,
            )
        beta = np.array(
            0.0,
            dtype=np.double,
            )
        m = mat1.ncols if transpose1 else mat1.nrows
        n = mat2.nrows if transpose2 else mat2.ncols
        k1 = mat1.nrows if transpose1 else mat1.ncols
        k2 = mat2.ncols if transpose2 else mat2.nrows
        assert k1 == k2

        c = GPUMatrix(
            nrows=m,
            ncols=n,
            )

        cublas.dgemm(
            handle=cublas_handle,
            transa=cublas.Operation.T if transpose2 else cublas.Operation.N,
            transb=cublas.Operation.T if transpose1 else cublas.Operation.N,
            m=n,
            n=m,
            k=k1,
            alpha=alpha.ctypes.data,
            a=mat2.pointer,
            lda=mat2.ncols,
            b=mat1.pointer,
            ldb=mat1.ncols,
            beta=beta.ctypes.data,
            c=c.pointer,
            ldc=c.ncols,
            )

        return c

    @staticmethod
    def ddot(
        *,
        x,
        y,
        ):

        result = np.empty(1, dtype=np.double)

        cublas.ddot(
            handle = cublas_handle,
            n=x.size,
            x=x.pointer,
            incx=1,
            y=y.pointer,
            incy=1,
            result=result.ctypes.data,
            )
        return result[0]


ddot

        cublas.dgemm(
            handle=cublas_handle,
            transa=cublas.Operation.T if transpose2 else cublas.Operation.N,
            transb=cublas.Operation.T if transpose1 else cublas.Operation.N,
            m=n,
            n=m,
            k=k1,
            alpha=alpha.ctypes.data,
            a=mat2.pointer,
            lda=mat2.ncols,
            b=mat1.pointer,
            ldb=mat1.ncols,
            beta=beta.ctypes.data,
            c=c.pointer,
            ldc=c.ncols,
            )

        return c

    @staticmethod
    def ddot(
        *,
        x,
        y,
        ):

        result = np.empty(1, dtype=np.double)

        cublas.ddot(
            handle = cublas_handle,
            n=x.size,
            x=x.pointer,
            incx=1,
            y=y.pointer,
            incy=1,
            result=result.ctypes.data,
            )
        return result[0]

    @staticmethod
    def dgeam(
        *,
        transpose1,
        alpha,
        mat1,
        transpose2,
        beta,
        mat2,
        ):

        assert mat1.nrows == mat1.ncols
        assert mat2.nrows == mat2.ncols
        assert mat1.nrows == mat2.nrows

        C = mat1.clone()

        alpha=np.array(


dgeam

        *,
        x,
        y,
        ):

        result = np.empty(1, dtype=np.double)

        cublas.ddot(
            handle = cublas_handle,
            n=x.size,
            x=x.pointer,
            incx=1,
            y=y.pointer,
            incy=1,
            result=result.ctypes.data,
            )
        return result[0]

    @staticmethod
    def dgeam(
        *,
        transpose1,
        alpha,
        mat1,
        transpose2,
        beta,
        mat2,
        ):

        assert mat1.nrows == mat1.ncols
        assert mat2.nrows == mat2.ncols
        assert mat1.nrows == mat2.nrows

        C = mat1.clone()

        alpha=np.array(
            alpha,
            dtype=np.double,
            )
        beta=np.array(
            beta,
            dtype=np.double,
            )

        cublas.dgeam(
            handle=cublas_handle,
            transa=cublas.Operation.T if transpose1 else cublas.Operation.N,
            transb=cublas.Operation.T if transpose2 else cublas.Operation.N,
            m=mat1.nrows,
            n=mat2.ncols,
            alpha=alpha.ctypes.data,
            a=mat1.pointer,
            lda=mat1.ncols,
            beta=beta.ctypes.data,
            b=mat2.pointer,
            ldb=mat2.ncols,
            c=C.pointer,
            ldc=C.ncols,
            )

        return C

    @staticmethod
    def daxpy(
        *,
        alpha,
        x,
        y,
        ):

        alpha=np.array(
            alpha,
            dtype=np.double,
            )

        cublas.daxpy(
            handle=cublas_handle,
            n=x.size,
            alpha=alpha.ctypes.data,
            x=x.pointer,
            incx=1,


daxpy

        cublas.dgeam(
            handle=cublas_handle,
            transa=cublas.Operation.T if transpose1 else cublas.Operation.N,
            transb=cublas.Operation.T if transpose2 else cublas.Operation.N,
            m=mat1.nrows,
            n=mat2.ncols,
            alpha=alpha.ctypes.data,
            a=mat1.pointer,
            lda=mat1.ncols,
            beta=beta.ctypes.data,
            b=mat2.pointer,
            ldb=mat2.ncols,
            c=C.pointer,
            ldc=C.ncols,
            )

        return C

    @staticmethod
    def daxpy(
        *,
        alpha,
        x,
        y,
        ):

        alpha=np.array(
            alpha,
            dtype=np.double,
            )

        cublas.daxpy(
            handle=cublas_handle,
            n=x.size,
            alpha=alpha.ctypes.data,
            x=x.pointer,
            incx=1,
            y=y.pointer,
            incy=1,
            )

    @staticmethod
    def scale(
        *,
        matrix,
        scale,
        ):

        alpha=np.array(
            scale,
            dtype=np.double,
            )
        cublas.dscal(
            handle=cublas_handle,
            n=matrix.size,
            alpha=alpha.ctypes.data,
            x=matrix.pointer,
            incx=1,
            )


scale

        x,
        y,
        ):

        alpha=np.array(
            alpha,
            dtype=np.double,
            )

        cublas.daxpy(
            handle=cublas_handle,
            n=x.size,
            alpha=alpha.ctypes.data,
            x=x.pointer,
            incx=1,
            y=y.pointer,
            incy=1,
            )

    @staticmethod
    def scale(
        *,
        matrix,
        scale,
        ):

        alpha=np.array(
            scale,
            dtype=np.double,
            )
        cublas.dscal(
            handle=cublas_handle,
            n=matrix.size,
            alpha=alpha.ctypes.data,
            x=matrix.pointer,
            incx=1,
            )

    @staticmethod
    def eigh(
        *,
        matrix
        ):

        jobz = cusolver_base.EigMode.VECTOR
        uplo = cublas.FillMode.LOWER

        assert matrix.nrows == matrix.ncols

        evecs = matrix.clone()
        evals = GPUMatrix(
            nrows=matrix.nrows,
            ncols=1,
            dtype=matrix.dtype,
            initialize=False,
            )


eigh

    @staticmethod
    def scale(
        *,
        matrix,
        scale,
        ):

        alpha=np.array(
            scale,
            dtype=np.double,
            )
        cublas.dscal(
            handle=cublas_handle,
            n=matrix.size,
            alpha=alpha.ctypes.data,
            x=matrix.pointer,
            incx=1,
            )

    @staticmethod
    def eigh(
        *,
        matrix
        ):

        jobz = cusolver_base.EigMode.VECTOR
        uplo = cublas.FillMode.LOWER

        assert matrix.nrows == matrix.ncols

        evecs = matrix.clone()
        evals = GPUMatrix(
            nrows=matrix.nrows,
            ncols=1,
            dtype=matrix.dtype,
            initialize=False,
            )

        d_info = GPUMatrix(
            nrows=1,
            ncols=1,
            dtype=np.int64,
            )

        # Workspace query
        lwork = np.empty(
            1,
            dtype=np.int64
            )
        lwork = cusolver.dsyevd_buffer_size(
            handle=cusolver_handle,
            jobz=jobz,
            uplo=uplo,
            n=evecs.ncols,
            a=evecs.pointer,
            lda=evecs.ncols,
            w=evals.pointer,
        )

        d_work = GPUMatrix(
            nrows=lwork,
            ncols=1,
            dtype=np.double,
            )

        # Compute eigenvalues/eigenvectors in-place
        cusolver.dsyevd(
            handle=cusolver_handle,
            jobz=jobz,
            uplo=uplo,
            n=evecs.ncols,
            a=evecs.pointer,
            lda=evecs.ncols,
            w=evals.pointer,
            work=d_work.pointer,
            lwork=lwork,
            info=d_info.pointer,
        )

        info_host = d_info.to_numpy()
        if info_host[0, 0] != 0:
            raise RuntimeError(f"dsyevd failed with info = {info_host[0, 0]}")

        evecs = GPUMatrixUtility.dgeam(
            transpose1=True,
            alpha=1.0,
            mat1=evecs,
            transpose2=False,
            beta=0.0,
            mat2=evecs,
            )

        return evals, evecs


# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# 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
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cuest.bindings as ce

from .cuest_workspace_descriptor import CuestWorkspaceDescriptor
from .cuest_workspace import CuestWorkspace

from .cuest_handle import CuestHandle
from .cuest_ao_basis import CuestAOBasis
from .cuest_ao_pair_list import CuestAOPairList

from .cuest_parameters import CuestParameters

class CuestOEIntPlan(object):

    def __init__(
        self,
        *,
        handle : CuestHandle,
        basis : CuestAOBasis,
        ao_pair_list : CuestAOPairList,
        ):

        self.initialized = False

        self.handle = handle

        oe_int_plan_parameters = CuestParameters(
            parametersType=ce.CuestParametersType.CUEST_OEINTPLAN_PARAMETERS,
            )

        self.oe_int_plan_handle = ce.cuestOEIntPlanHandle()

        # => Workspace Query <= #

        persistent_workspace_descriptor = CuestWorkspaceDescriptor()
        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestOEIntPlanCreateWorkspaceQuery(
            handle=handle.handle,
            basis=basis.ao_basis_handle,
            pairList=ao_pair_list.ao_pair_list_handle,
            parameters=oe_int_plan_parameters.parameters,
            persistentWorkspaceDescriptor=persistent_workspace_descriptor.pointer,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            outPlan=self.oe_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOEIntPlanCreateWorkspaceQuery failed')

        persistent_workspace = CuestWorkspace(workspaceDescriptor=persistent_workspace_descriptor)
        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        # => Creation <= #

        status = ce.cuestOEIntPlanCreate(
            handle=handle.handle,
            basis=basis.ao_basis_handle,
            pairList=ao_pair_list.ao_pair_list_handle,
            parameters=oe_int_plan_parameters.parameters,
            persistentWorkspace=persistent_workspace.pointer,
            temporaryWorkspace=temporary_workspace.pointer,
            outPlan=self.oe_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOEIntPlanCreate failed')

        # Bind the lifetime of persistent_workspace to this object
        self.persistent_workspace = persistent_workspace

        self.initialized = True

    def __del__(self):

        if not self.initialized: return

        status = ce.cuestOEIntPlanDestroy(
            handle=self.oe_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOEIntPlanDestroy failed')


CuestOEIntPlan

#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cuest.bindings as ce

from .cuest_workspace_descriptor import CuestWorkspaceDescriptor
from .cuest_workspace import CuestWorkspace

from .cuest_handle import CuestHandle
from .cuest_ao_basis import CuestAOBasis
from .cuest_ao_pair_list import CuestAOPairList

from .cuest_parameters import CuestParameters

class CuestOEIntPlan(object):

    def __init__(
        self,
        *,
        handle : CuestHandle,
        basis : CuestAOBasis,
        ao_pair_list : CuestAOPairList,
        ):

        self.initialized = False

        self.handle = handle

        oe_int_plan_parameters = CuestParameters(
            parametersType=ce.CuestParametersType.CUEST_OEINTPLAN_PARAMETERS,
            )

        self.oe_int_plan_handle = ce.cuestOEIntPlanHandle()

        # => Workspace Query <= #

        persistent_workspace_descriptor = CuestWorkspaceDescriptor()
        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestOEIntPlanCreateWorkspaceQuery(
            handle=handle.handle,
            basis=basis.ao_basis_handle,
            pairList=ao_pair_list.ao_pair_list_handle,
            parameters=oe_int_plan_parameters.parameters,
            persistentWorkspaceDescriptor=persistent_workspace_descriptor.pointer,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            outPlan=self.oe_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOEIntPlanCreateWorkspaceQuery failed')

        persistent_workspace = CuestWorkspace(workspaceDescriptor=persistent_workspace_descriptor)
        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        # => Creation <= #

        status = ce.cuestOEIntPlanCreate(
            handle=handle.handle,
            basis=basis.ao_basis_handle,
            pairList=ao_pair_list.ao_pair_list_handle,
            parameters=oe_int_plan_parameters.parameters,
            persistentWorkspace=persistent_workspace.pointer,
            temporaryWorkspace=temporary_workspace.pointer,
            outPlan=self.oe_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOEIntPlanCreate failed')

        # Bind the lifetime of persistent_workspace to this object
        self.persistent_workspace = persistent_workspace

        self.initialized = True

    def __del__(self):

        if not self.initialized: return

        status = ce.cuestOEIntPlanDestroy(
            handle=self.oe_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOEIntPlanDestroy failed')


#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cuest.bindings as ce

from .cuest_workspace_descriptor import CuestWorkspaceDescriptor
from .cuest_workspace import CuestWorkspace

from .cuest_handle import CuestHandle
from .cuest_ao_basis import CuestAOBasis
from .cuest_ao_pair_list import CuestAOPairList

from .cuest_parameters import CuestParameters

class CuestOEIntPlan(object):

    def __init__(
        self,
        *,
        handle : CuestHandle,
        basis : CuestAOBasis,
        ao_pair_list : CuestAOPairList,
        ):

        self.initialized = False

        self.handle = handle

        oe_int_plan_parameters = CuestParameters(
            parametersType=ce.CuestParametersType.CUEST_OEINTPLAN_PARAMETERS,
            )

        self.oe_int_plan_handle = ce.cuestOEIntPlanHandle()

        # => Workspace Query <= #

        persistent_workspace_descriptor = CuestWorkspaceDescriptor()
        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestOEIntPlanCreateWorkspaceQuery(
            handle=handle.handle,
            basis=basis.ao_basis_handle,
            pairList=ao_pair_list.ao_pair_list_handle,
            parameters=oe_int_plan_parameters.parameters,
            persistentWorkspaceDescriptor=persistent_workspace_descriptor.pointer,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            outPlan=self.oe_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOEIntPlanCreateWorkspaceQuery failed')

        persistent_workspace = CuestWorkspace(workspaceDescriptor=persistent_workspace_descriptor)
        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        # => Creation <= #

        status = ce.cuestOEIntPlanCreate(
            handle=handle.handle,
            basis=basis.ao_basis_handle,
            pairList=ao_pair_list.ao_pair_list_handle,
            parameters=oe_int_plan_parameters.parameters,
            persistentWorkspace=persistent_workspace.pointer,
            temporaryWorkspace=temporary_workspace.pointer,
            outPlan=self.oe_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOEIntPlanCreate failed')

        # Bind the lifetime of persistent_workspace to this object
        self.persistent_workspace = persistent_workspace

        self.initialized = True

    def __del__(self):

        if not self.initialized: return

        status = ce.cuestOEIntPlanDestroy(
            handle=self.oe_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOEIntPlanDestroy failed')


        # => Creation <= #

        status = ce.cuestOEIntPlanCreate(
            handle=handle.handle,
            basis=basis.ao_basis_handle,
            pairList=ao_pair_list.ao_pair_list_handle,
            parameters=oe_int_plan_parameters.parameters,
            persistentWorkspace=persistent_workspace.pointer,
            temporaryWorkspace=temporary_workspace.pointer,
            outPlan=self.oe_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOEIntPlanCreate failed')

        # Bind the lifetime of persistent_workspace to this object
        self.persistent_workspace = persistent_workspace

        self.initialized = True

    def __del__(self):

        if not self.initialized: return

        status = ce.cuestOEIntPlanDestroy(
            handle=self.oe_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestOEIntPlanDestroy failed')


# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# 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
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cuest.bindings as ce

from .cuest_handle import CuestHandle
from .cuest_df_int_plan import CuestDFIntPlan

from .cuest_workspace_descriptor import CuestWorkspaceDescriptor
from .cuest_workspace import CuestWorkspace
from .cuest_parameters import CuestParameters

import numpy as np

class CuestDFIntCompute(object):

    @staticmethod
    def coulomb(
        *,
        handle : CuestHandle,
        df_int_plan : CuestDFIntPlan,
        Dptr,
        Jptr,
        ):

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        Jptr2 = ce.Pointer()
        Jptr2.value = np.intp(Jptr)

        # => Workspace query <= #

        dfj_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_DFCOULOMBCOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestDFCoulombComputeWorkspaceQuery(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=dfj_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityMatrix=Dptr2,
            outCoulombMatrix=Jptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFCoulombComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestDFCoulombCompute(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=dfj_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Dptr2,
            outCoulombMatrix=Jptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFCoulombCompute failed')
        del dfj_compute_parameters

    @staticmethod
    def symmetric_exchange(
        *,
        handle : CuestHandle,
        df_int_plan : CuestDFIntPlan,
        nocc,
        Coccptr,
        Kptr,
        dfk_int8_slice_count,
        dfk_int8_modulus_count,
        ):

        Coccptr2 = ce.Pointer()
        Coccptr2.value = np.intp(Coccptr)

        Kptr2 = ce.Pointer()
        Kptr2.value = np.intp(Kptr)

        # => Workspace query <= #

        dfk_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICEXCHANGECOMPUTE_PARAMETERS)

        slice_count = ce.data_uint64_t(dfk_int8_slice_count)
        modulus_count = ce.data_uint64_t(dfk_int8_modulus_count)

        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICEXCHANGECOMPUTE_PARAMETERS,
            parameters=dfk_compute_parameters.parameters,
            attribute=ce.CuestDFSymmetricExchangeComputeParametersAttributes.CUEST_DFSYMMETRICEXCHANGECOMPUTE_PARAMETERS_INT8_SLICE_COUNT,
            attributeValue=slice_count,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed')

        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICEXCHANGECOMPUTE_PARAMETERS,
            parameters=dfk_compute_parameters.parameters,
            attribute=ce.CuestDFSymmetricExchangeComputeParametersAttributes.CUEST_DFSYMMETRICEXCHANGECOMPUTE_PARAMETERS_INT8_MODULUS_COUNT,
            attributeValue=modulus_count,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed')

        # Allow the algorithm to use up to 2GB of DRAM
        # NOTE: Production codes may wish to configure the maximum temporary
        # workspace memory as a user parameter or heuristic
        exchangeint_variable_buffer_descriptor = CuestWorkspaceDescriptor(
            deviceBufferSizeInBytes=2000000000,
            )

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestDFSymmetricExchangeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=dfk_compute_parameters.parameters,
            variableBufferSize=exchangeint_variable_buffer_descriptor.pointer,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            numOccupied=nocc,
            coefficientMatrix=Coccptr2,
            outExchangeMatrix=Kptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFExchangeComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestDFSymmetricExchangeCompute(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=dfk_compute_parameters.parameters,
            variableBufferSize=exchangeint_variable_buffer_descriptor.pointer,
            temporaryWorkspace=temporary_workspace.pointer,
            numOccupied=nocc,
            coefficientMatrix=Coccptr2,
            outExchangeMatrix=Kptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFExchangeCompute failed')
        del dfk_compute_parameters

    @staticmethod
    def coulomb_and_exchange_gradient(
        *,
        handle : CuestHandle,
        df_int_plan : CuestDFIntPlan,
        scaleJ,
        DJptr,
        scaleK,
        noccsK,
        CoccsKptr,
        Gptr,
        ):

        DJptr2 = ce.Pointer()
        DJptr2.value = np.intp(DJptr)

        CoccsKptr2 = ce.Pointer()
        CoccsKptr2.value = np.intp(CoccsKptr)

        Gptr2 = ce.Pointer()
        Gptr2.value = np.intp(Gptr)

        # => Workspace query <= #

        df_grad_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_PARAMETERS)

        # Allow the algorithm to use up to 2GB of DRAM
        # NOTE: Production codes may wish to configure the maximum temporary
        # workspace memory as a user parameter or heuristic
        variable_buffer_descriptor = CuestWorkspaceDescriptor(
            deviceBufferSizeInBytes=2000000000,
            )

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        memory_policy_data = ce.data_cuestDFSymmetricDerivativeComputeMemoryPolicy_t(ce.CuestDFSymmetricDerivativeComputeMemoryPolicy.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_MEMORY_POLICY_FULL)
        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_PARAMETERS,
            parameters=df_grad_compute_parameters.parameters,
            attribute=ce.CuestDFSymmetricDerivativeComputeParametersAttributes.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_PARAMETERS_MEMORY_POLICY,
            attributeValue=memory_policy_data,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed')

        status = ce.cuestDFSymmetricDerivativeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=df_grad_compute_parameters.parameters,
            variableBufferSize=variable_buffer_descriptor.pointer,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityScale=scaleJ,
            densityMatrix=DJptr2,
            coefficientScale=scaleK,
            numCoefficientMatrices=len(noccsK),
            numOccupied=noccsK,
            coefficientMatrices=CoccsKptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFSymmetricDerivativeComputeWorkspaceQuery failed')

        try:
            temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        except RuntimeError:
            memory_policy_data = ce.data_cuestDFSymmetricDerivativeComputeMemoryPolicy_t(ce.CuestDFSymmetricDerivativeComputeMemoryPolicy.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_MEMORY_POLICY_BLOCKED)
            status = ce.cuestParametersConfigure(
                parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_PARAMETERS,
                parameters=df_grad_compute_parameters.parameters,
                attribute=ce.CuestDFSymmetricDerivativeComputeParametersAttributes.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_PARAMETERS_MEMORY_POLICY,
                attributeValue=memory_policy_data,
                )
            if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
                raise RuntimeError('cuestParametersConfigure failed')

            status = ce.cuestDFSymmetricDerivativeComputeWorkspaceQuery(
                handle=handle.handle,
                plan=df_int_plan.df_int_plan_handle,
                parameters=df_grad_compute_parameters.parameters,
                variableBufferSize=variable_buffer_descriptor.pointer,
                temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
                densityScale=scaleJ,
                densityMatrix=DJptr2,
                coefficientScale=scaleK,
                numCoefficientMatrices=len(noccsK),
                numOccupied=noccsK,
                coefficientMatrices=CoccsKptr2,
                outGradient=Gptr2,
                )

            if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
                raise RuntimeError('cuestDFSymmetricDerivativeComputeWorkspaceQuery failed')

            try:
                temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

            except RuntimeError:
                raise RuntimeError('Cannot allocate memory for cuestDFSymmetricDerivativeCompute')

        status = ce.cuestDFSymmetricDerivativeCompute(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=df_grad_compute_parameters.parameters,
            variableBufferSize=variable_buffer_descriptor.pointer,
            temporaryWorkspace=temporary_workspace.pointer,
            densityScale=scaleJ,
            densityMatrix=DJptr2,
            coefficientScale=scaleK,
            numCoefficientMatrices=len(noccsK),
            numOccupied=noccsK,
            coefficientMatrices=CoccsKptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFSymmetricDerivativeCompute failed')
        del df_grad_compute_parameters


CuestDFIntCompute

#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cuest.bindings as ce

from .cuest_handle import CuestHandle
from .cuest_df_int_plan import CuestDFIntPlan

from .cuest_workspace_descriptor import CuestWorkspaceDescriptor
from .cuest_workspace import CuestWorkspace
from .cuest_parameters import CuestParameters

import numpy as np

class CuestDFIntCompute(object):

    @staticmethod
    def coulomb(
        *,
        handle : CuestHandle,
        df_int_plan : CuestDFIntPlan,
        Dptr,
        Jptr,
        ):

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        Jptr2 = ce.Pointer()
        Jptr2.value = np.intp(Jptr)

        # => Workspace query <= #

        dfj_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_DFCOULOMBCOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestDFCoulombComputeWorkspaceQuery(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=dfj_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityMatrix=Dptr2,
            outCoulombMatrix=Jptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFCoulombComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestDFCoulombCompute(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=dfj_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Dptr2,
            outCoulombMatrix=Jptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFCoulombCompute failed')
        del dfj_compute_parameters

    @staticmethod
    def symmetric_exchange(
        *,
        handle : CuestHandle,
        df_int_plan : CuestDFIntPlan,
        nocc,
        Coccptr,
        Kptr,
        dfk_int8_slice_count,
        dfk_int8_modulus_count,
        ):

        Coccptr2 = ce.Pointer()
        Coccptr2.value = np.intp(Coccptr)

        Kptr2 = ce.Pointer()
        Kptr2.value = np.intp(Kptr)

        # => Workspace query <= #

        dfk_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICEXCHANGECOMPUTE_PARAMETERS)

        slice_count = ce.data_uint64_t(dfk_int8_slice_count)
        modulus_count = ce.data_uint64_t(dfk_int8_modulus_count)

        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICEXCHANGECOMPUTE_PARAMETERS,
            parameters=dfk_compute_parameters.parameters,
            attribute=ce.CuestDFSymmetricExchangeComputeParametersAttributes.CUEST_DFSYMMETRICEXCHANGECOMPUTE_PARAMETERS_INT8_SLICE_COUNT,
            attributeValue=slice_count,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed')

        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICEXCHANGECOMPUTE_PARAMETERS,
            parameters=dfk_compute_parameters.parameters,
            attribute=ce.CuestDFSymmetricExchangeComputeParametersAttributes.CUEST_DFSYMMETRICEXCHANGECOMPUTE_PARAMETERS_INT8_MODULUS_COUNT,
            attributeValue=modulus_count,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed')

        # Allow the algorithm to use up to 2GB of DRAM
        # NOTE: Production codes may wish to configure the maximum temporary
        # workspace memory as a user parameter or heuristic
        exchangeint_variable_buffer_descriptor = CuestWorkspaceDescriptor(
            deviceBufferSizeInBytes=2000000000,
            )

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestDFSymmetricExchangeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=dfk_compute_parameters.parameters,
            variableBufferSize=exchangeint_variable_buffer_descriptor.pointer,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            numOccupied=nocc,
            coefficientMatrix=Coccptr2,
            outExchangeMatrix=Kptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFExchangeComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestDFSymmetricExchangeCompute(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=dfk_compute_parameters.parameters,
            variableBufferSize=exchangeint_variable_buffer_descriptor.pointer,
            temporaryWorkspace=temporary_workspace.pointer,
            numOccupied=nocc,
            coefficientMatrix=Coccptr2,
            outExchangeMatrix=Kptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFExchangeCompute failed')
        del dfk_compute_parameters

    @staticmethod
    def coulomb_and_exchange_gradient(
        *,
        handle : CuestHandle,
        df_int_plan : CuestDFIntPlan,
        scaleJ,
        DJptr,
        scaleK,
        noccsK,
        CoccsKptr,
        Gptr,
        ):

        DJptr2 = ce.Pointer()
        DJptr2.value = np.intp(DJptr)

        CoccsKptr2 = ce.Pointer()
        CoccsKptr2.value = np.intp(CoccsKptr)

        Gptr2 = ce.Pointer()
        Gptr2.value = np.intp(Gptr)

        # => Workspace query <= #

        df_grad_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_PARAMETERS)

        # Allow the algorithm to use up to 2GB of DRAM
        # NOTE: Production codes may wish to configure the maximum temporary
        # workspace memory as a user parameter or heuristic
        variable_buffer_descriptor = CuestWorkspaceDescriptor(
            deviceBufferSizeInBytes=2000000000,
            )

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        memory_policy_data = ce.data_cuestDFSymmetricDerivativeComputeMemoryPolicy_t(ce.CuestDFSymmetricDerivativeComputeMemoryPolicy.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_MEMORY_POLICY_FULL)
        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_PARAMETERS,
            parameters=df_grad_compute_parameters.parameters,
            attribute=ce.CuestDFSymmetricDerivativeComputeParametersAttributes.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_PARAMETERS_MEMORY_POLICY,
            attributeValue=memory_policy_data,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed')

        status = ce.cuestDFSymmetricDerivativeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=df_grad_compute_parameters.parameters,
            variableBufferSize=variable_buffer_descriptor.pointer,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityScale=scaleJ,
            densityMatrix=DJptr2,
            coefficientScale=scaleK,
            numCoefficientMatrices=len(noccsK),
            numOccupied=noccsK,
            coefficientMatrices=CoccsKptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFSymmetricDerivativeComputeWorkspaceQuery failed')

        try:
            temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        except RuntimeError:
            memory_policy_data = ce.data_cuestDFSymmetricDerivativeComputeMemoryPolicy_t(ce.CuestDFSymmetricDerivativeComputeMemoryPolicy.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_MEMORY_POLICY_BLOCKED)
            status = ce.cuestParametersConfigure(
                parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_PARAMETERS,
                parameters=df_grad_compute_parameters.parameters,
                attribute=ce.CuestDFSymmetricDerivativeComputeParametersAttributes.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_PARAMETERS_MEMORY_POLICY,
                attributeValue=memory_policy_data,
                )
            if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
                raise RuntimeError('cuestParametersConfigure failed')

            status = ce.cuestDFSymmetricDerivativeComputeWorkspaceQuery(
                handle=handle.handle,
                plan=df_int_plan.df_int_plan_handle,
                parameters=df_grad_compute_parameters.parameters,
                variableBufferSize=variable_buffer_descriptor.pointer,
                temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
                densityScale=scaleJ,
                densityMatrix=DJptr2,
                coefficientScale=scaleK,
                numCoefficientMatrices=len(noccsK),
                numOccupied=noccsK,
                coefficientMatrices=CoccsKptr2,
                outGradient=Gptr2,
                )

            if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
                raise RuntimeError('cuestDFSymmetricDerivativeComputeWorkspaceQuery failed')

            try:
                temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

            except RuntimeError:
                raise RuntimeError('Cannot allocate memory for cuestDFSymmetricDerivativeCompute')

        status = ce.cuestDFSymmetricDerivativeCompute(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=df_grad_compute_parameters.parameters,
            variableBufferSize=variable_buffer_descriptor.pointer,
            temporaryWorkspace=temporary_workspace.pointer,
            densityScale=scaleJ,
            densityMatrix=DJptr2,
            coefficientScale=scaleK,
            numCoefficientMatrices=len(noccsK),
            numOccupied=noccsK,
            coefficientMatrices=CoccsKptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFSymmetricDerivativeCompute failed')
        del df_grad_compute_parameters


coulomb

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cuest.bindings as ce

from .cuest_handle import CuestHandle
from .cuest_df_int_plan import CuestDFIntPlan

from .cuest_workspace_descriptor import CuestWorkspaceDescriptor
from .cuest_workspace import CuestWorkspace
from .cuest_parameters import CuestParameters

import numpy as np

class CuestDFIntCompute(object):

    @staticmethod
    def coulomb(
        *,
        handle : CuestHandle,
        df_int_plan : CuestDFIntPlan,
        Dptr,
        Jptr,
        ):

        Dptr2 = ce.Pointer()
        Dptr2.value = np.intp(Dptr)

        Jptr2 = ce.Pointer()
        Jptr2.value = np.intp(Jptr)

        # => Workspace query <= #

        dfj_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_DFCOULOMBCOMPUTE_PARAMETERS)

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestDFCoulombComputeWorkspaceQuery(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=dfj_compute_parameters.parameters,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityMatrix=Dptr2,
            outCoulombMatrix=Jptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFCoulombComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestDFCoulombCompute(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=dfj_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Dptr2,
            outCoulombMatrix=Jptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFCoulombCompute failed')
        del dfj_compute_parameters

    @staticmethod
    def symmetric_exchange(
        *,
        handle : CuestHandle,
        df_int_plan : CuestDFIntPlan,
        nocc,
        Coccptr,
        Kptr,
        dfk_int8_slice_count,
        dfk_int8_modulus_count,
        ):

        Coccptr2 = ce.Pointer()
        Coccptr2.value = np.intp(Coccptr)

        Kptr2 = ce.Pointer()
        Kptr2.value = np.intp(Kptr)


        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFCoulombComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestDFCoulombCompute(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=dfj_compute_parameters.parameters,
            temporaryWorkspace=temporary_workspace.pointer,
            densityMatrix=Dptr2,
            outCoulombMatrix=Jptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFCoulombCompute failed')
        del dfj_compute_parameters

    @staticmethod
    def symmetric_exchange(
        *,
        handle : CuestHandle,
        df_int_plan : CuestDFIntPlan,
        nocc,
        Coccptr,
        Kptr,
        dfk_int8_slice_count,
        dfk_int8_modulus_count,
        ):

        Coccptr2 = ce.Pointer()
        Coccptr2.value = np.intp(Coccptr)

        Kptr2 = ce.Pointer()
        Kptr2.value = np.intp(Kptr)

        # => Workspace query <= #

        dfk_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICEXCHANGECOMPUTE_PARAMETERS)

        slice_count = ce.data_uint64_t(dfk_int8_slice_count)
        modulus_count = ce.data_uint64_t(dfk_int8_modulus_count)

        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICEXCHANGECOMPUTE_PARAMETERS,
            parameters=dfk_compute_parameters.parameters,
            attribute=ce.CuestDFSymmetricExchangeComputeParametersAttributes.CUEST_DFSYMMETRICEXCHANGECOMPUTE_PARAMETERS_INT8_SLICE_COUNT,
            attributeValue=slice_count,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed')

        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICEXCHANGECOMPUTE_PARAMETERS,
            parameters=dfk_compute_parameters.parameters,
            attribute=ce.CuestDFSymmetricExchangeComputeParametersAttributes.CUEST_DFSYMMETRICEXCHANGECOMPUTE_PARAMETERS_INT8_MODULUS_COUNT,
            attributeValue=modulus_count,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed')

        # Allow the algorithm to use up to 2GB of DRAM
        # NOTE: Production codes may wish to configure the maximum temporary
        # workspace memory as a user parameter or heuristic
        exchangeint_variable_buffer_descriptor = CuestWorkspaceDescriptor(
            deviceBufferSizeInBytes=2000000000,
            )

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestDFSymmetricExchangeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=dfk_compute_parameters.parameters,
            variableBufferSize=exchangeint_variable_buffer_descriptor.pointer,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            numOccupied=nocc,
            coefficientMatrix=Coccptr2,
            outExchangeMatrix=Kptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFExchangeComputeWorkspaceQuery failed')

        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestDFSymmetricExchangeCompute(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=dfk_compute_parameters.parameters,
            variableBufferSize=exchangeint_variable_buffer_descriptor.pointer,
            temporaryWorkspace=temporary_workspace.pointer,
            numOccupied=nocc,
            coefficientMatrix=Coccptr2,
            outExchangeMatrix=Kptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFExchangeCompute failed')
        del dfk_compute_parameters

    @staticmethod
    def coulomb_and_exchange_gradient(
        *,
        handle : CuestHandle,
        df_int_plan : CuestDFIntPlan,
        scaleJ,
        DJptr,
        scaleK,
        noccsK,
        CoccsKptr,
        Gptr,
        ):

        DJptr2 = ce.Pointer()
        DJptr2.value = np.intp(DJptr)

        CoccsKptr2 = ce.Pointer()
        CoccsKptr2.value = np.intp(CoccsKptr)


        temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        status = ce.cuestDFSymmetricExchangeCompute(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=dfk_compute_parameters.parameters,
            variableBufferSize=exchangeint_variable_buffer_descriptor.pointer,
            temporaryWorkspace=temporary_workspace.pointer,
            numOccupied=nocc,
            coefficientMatrix=Coccptr2,
            outExchangeMatrix=Kptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFExchangeCompute failed')
        del dfk_compute_parameters

    @staticmethod
    def coulomb_and_exchange_gradient(
        *,
        handle : CuestHandle,
        df_int_plan : CuestDFIntPlan,
        scaleJ,
        DJptr,
        scaleK,
        noccsK,
        CoccsKptr,
        Gptr,
        ):

        DJptr2 = ce.Pointer()
        DJptr2.value = np.intp(DJptr)

        CoccsKptr2 = ce.Pointer()
        CoccsKptr2.value = np.intp(CoccsKptr)

        Gptr2 = ce.Pointer()
        Gptr2.value = np.intp(Gptr)

        # => Workspace query <= #

        df_grad_compute_parameters = CuestParameters(parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_PARAMETERS)

        # Allow the algorithm to use up to 2GB of DRAM
        # NOTE: Production codes may wish to configure the maximum temporary
        # workspace memory as a user parameter or heuristic
        variable_buffer_descriptor = CuestWorkspaceDescriptor(
            deviceBufferSizeInBytes=2000000000,
            )

        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        memory_policy_data = ce.data_cuestDFSymmetricDerivativeComputeMemoryPolicy_t(ce.CuestDFSymmetricDerivativeComputeMemoryPolicy.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_MEMORY_POLICY_FULL)
        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_PARAMETERS,
            parameters=df_grad_compute_parameters.parameters,
            attribute=ce.CuestDFSymmetricDerivativeComputeParametersAttributes.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_PARAMETERS_MEMORY_POLICY,
            attributeValue=memory_policy_data,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed')

        status = ce.cuestDFSymmetricDerivativeComputeWorkspaceQuery(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=df_grad_compute_parameters.parameters,
            variableBufferSize=variable_buffer_descriptor.pointer,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            densityScale=scaleJ,
            densityMatrix=DJptr2,
            coefficientScale=scaleK,
            numCoefficientMatrices=len(noccsK),
            numOccupied=noccsK,
            coefficientMatrices=CoccsKptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFSymmetricDerivativeComputeWorkspaceQuery failed')

        try:
            temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

        except RuntimeError:
            memory_policy_data = ce.data_cuestDFSymmetricDerivativeComputeMemoryPolicy_t(ce.CuestDFSymmetricDerivativeComputeMemoryPolicy.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_MEMORY_POLICY_BLOCKED)
            status = ce.cuestParametersConfigure(
                parametersType=ce.CuestParametersType.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_PARAMETERS,
                parameters=df_grad_compute_parameters.parameters,
                attribute=ce.CuestDFSymmetricDerivativeComputeParametersAttributes.CUEST_DFSYMMETRICDERIVATIVECOMPUTE_PARAMETERS_MEMORY_POLICY,
                attributeValue=memory_policy_data,
                )
            if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
                raise RuntimeError('cuestParametersConfigure failed')

            status = ce.cuestDFSymmetricDerivativeComputeWorkspaceQuery(
                handle=handle.handle,
                plan=df_int_plan.df_int_plan_handle,
                parameters=df_grad_compute_parameters.parameters,
                variableBufferSize=variable_buffer_descriptor.pointer,
                temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
                densityScale=scaleJ,
                densityMatrix=DJptr2,
                coefficientScale=scaleK,
                numCoefficientMatrices=len(noccsK),
                numOccupied=noccsK,
                coefficientMatrices=CoccsKptr2,
                outGradient=Gptr2,
                )

            if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
                raise RuntimeError('cuestDFSymmetricDerivativeComputeWorkspaceQuery failed')

            try:
                temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)

            except RuntimeError:
                raise RuntimeError('Cannot allocate memory for cuestDFSymmetricDerivativeCompute')

        status = ce.cuestDFSymmetricDerivativeCompute(
            handle=handle.handle,
            plan=df_int_plan.df_int_plan_handle,
            parameters=df_grad_compute_parameters.parameters,
            variableBufferSize=variable_buffer_descriptor.pointer,
            temporaryWorkspace=temporary_workspace.pointer,
            densityScale=scaleJ,
            densityMatrix=DJptr2,
            coefficientScale=scaleK,
            numCoefficientMatrices=len(noccsK),
            numOccupied=noccsK,
            coefficientMatrices=CoccsKptr2,
            outGradient=Gptr2,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFSymmetricDerivativeCompute failed')
        del df_grad_compute_parameters


# Copyright 2025-2026 NVIDIA CORPORATION & AFFILIATES.
#
# 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
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cuest.bindings as ce

class CuestResults(object):

    def __init__(
        self,
        *,
        resultsType,
        results_handle,
        ):

        self.initialized = False

        self.resultsType = resultsType
        self.results = results_handle

        status = ce.cuestResultsCreate(
            resultsType=self.resultsType,
            outResults=self.results,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsCreate failed: %d' % status)

        self.initialized = True

    def __del__(self):

        if not self.initialized: return

        status = ce.cuestResultsDestroy(
            resultsType=self.resultsType,
            results=self.results,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsDestroy failed: %d' % status)


        *,
        resultsType,
        results_handle,
        ):

        self.initialized = False

        self.resultsType = resultsType
        self.results = results_handle

        status = ce.cuestResultsCreate(
            resultsType=self.resultsType,
            outResults=self.results,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsCreate failed: %d' % status)

        self.initialized = True

    def __del__(self):

        if not self.initialized: return

        status = ce.cuestResultsDestroy(
            resultsType=self.resultsType,
            results=self.results,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestResultsDestroy failed: %d' % status)


# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# 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
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cuest.bindings as ce

from .cuest_workspace_descriptor import CuestWorkspaceDescriptor
from .cuest_workspace import CuestWorkspace

from .cuest_handle import CuestHandle
from .cuest_ao_basis import CuestAOBasis
from .cuest_ao_pair_list import CuestAOPairList

from .cuest_parameters import CuestParameters

class CuestDFIntPlan(object):

    def __init__(
        self,
        *,
        handle : CuestHandle,
        primary : CuestAOBasis,
        auxiliary : CuestAOBasis,
        ao_pair_list : CuestAOPairList,
        exchange_scale : float = 1.0,
        df_fitting_eigenvalue_cutoff : float = 1.0e-12,
        ):

        self.initialized = False

        self.handle = handle
        self.exchange_scale = exchange_scale
        self.df_fitting_eigenvalue_cutoff = df_fitting_eigenvalue_cutoff

        # NOTE: The CuestDFIntPlan has several defaultable parameters that
        # production codes may wish to override and expose as user-accessible
        # parameters.

        df_int_plan_parameters = CuestParameters(
            parametersType=ce.CuestParametersType.CUEST_DFINTPLAN_PARAMETERS,
            )

        exchange_scale_data = ce.data_double(self.exchange_scale)
        df_fitting_eigenvalue_cutoff_data = ce.data_double(self.df_fitting_eigenvalue_cutoff)

        self.df_int_plan_handle = ce.cuestDFIntPlanHandle()
        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_DFINTPLAN_PARAMETERS,
            parameters=df_int_plan_parameters.parameters,
            attribute=ce.CuestDFIntPlanParametersAttributes.CUEST_DFINTPLAN_PARAMETERS_EXCHANGE_FRACTION,
            attributeValue=exchange_scale_data,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed')

        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_DFINTPLAN_PARAMETERS,
            parameters=df_int_plan_parameters.parameters,
            attribute=ce.CuestDFIntPlanParametersAttributes.CUEST_DFINTPLAN_PARAMETERS_FITTING_CUTOFF,
            attributeValue=df_fitting_eigenvalue_cutoff_data,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed')

        # => Workspace Query <= #

        persistent_workspace_descriptor = CuestWorkspaceDescriptor()
        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestDFIntPlanCreateWorkspaceQuery(
            handle=handle.handle,
            primaryBasis=primary.ao_basis_handle,
            auxiliaryBasis=auxiliary.ao_basis_handle,
            pairList=ao_pair_list.ao_pair_list_handle,
            parameters=df_int_plan_parameters.parameters,
            persistentWorkspaceDescriptor=persistent_workspace_descriptor.pointer,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            outPlan=self.df_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFIntPlanCreateWorkspaceQuery failed')

        # Most likely place to run out of device memory, so we will add a custom RuntimeError
        try:
            persistent_workspace = CuestWorkspace(workspaceDescriptor=persistent_workspace_descriptor)
            temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)
        except RuntimeError as e:
            raise RuntimeError("CuestDFIntPlan workspace allocation failed - out of memory for CoreDF") from e

        # => Creation <= #

        status = ce.cuestDFIntPlanCreate(
            handle=handle.handle,
            primaryBasis=primary.ao_basis_handle,
            auxiliaryBasis=auxiliary.ao_basis_handle,
            pairList=ao_pair_list.ao_pair_list_handle,
            parameters=df_int_plan_parameters.parameters,
            persistentWorkspace=persistent_workspace.pointer,
            temporaryWorkspace=temporary_workspace.pointer,
            outPlan=self.df_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFIntPlanCreate failed')

        # Bind the lifetime of persistent_workspace to this object
        self.persistent_workspace = persistent_workspace

        self.initialized = True

    def __del__(self):

        if not self.initialized: return

        status = ce.cuestDFIntPlanDestroy(
            handle=self.df_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFIntPlanDestroy failed')


CuestDFIntPlan

#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cuest.bindings as ce

from .cuest_workspace_descriptor import CuestWorkspaceDescriptor
from .cuest_workspace import CuestWorkspace

from .cuest_handle import CuestHandle
from .cuest_ao_basis import CuestAOBasis
from .cuest_ao_pair_list import CuestAOPairList

from .cuest_parameters import CuestParameters

class CuestDFIntPlan(object):

    def __init__(
        self,
        *,
        handle : CuestHandle,
        primary : CuestAOBasis,
        auxiliary : CuestAOBasis,
        ao_pair_list : CuestAOPairList,
        exchange_scale : float = 1.0,
        df_fitting_eigenvalue_cutoff : float = 1.0e-12,
        ):

        self.initialized = False

        self.handle = handle
        self.exchange_scale = exchange_scale
        self.df_fitting_eigenvalue_cutoff = df_fitting_eigenvalue_cutoff

        # NOTE: The CuestDFIntPlan has several defaultable parameters that
        # production codes may wish to override and expose as user-accessible
        # parameters.

        df_int_plan_parameters = CuestParameters(
            parametersType=ce.CuestParametersType.CUEST_DFINTPLAN_PARAMETERS,
            )

        exchange_scale_data = ce.data_double(self.exchange_scale)
        df_fitting_eigenvalue_cutoff_data = ce.data_double(self.df_fitting_eigenvalue_cutoff)

        self.df_int_plan_handle = ce.cuestDFIntPlanHandle()
        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_DFINTPLAN_PARAMETERS,
            parameters=df_int_plan_parameters.parameters,
            attribute=ce.CuestDFIntPlanParametersAttributes.CUEST_DFINTPLAN_PARAMETERS_EXCHANGE_FRACTION,
            attributeValue=exchange_scale_data,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed')

        status = ce.cuestParametersConfigure(
            parametersType=ce.CuestParametersType.CUEST_DFINTPLAN_PARAMETERS,
            parameters=df_int_plan_parameters.parameters,
            attribute=ce.CuestDFIntPlanParametersAttributes.CUEST_DFINTPLAN_PARAMETERS_FITTING_CUTOFF,
            attributeValue=df_fitting_eigenvalue_cutoff_data,
            )
        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestParametersConfigure failed')

        # => Workspace Query <= #

        persistent_workspace_descriptor = CuestWorkspaceDescriptor()
        temporary_workspace_descriptor = CuestWorkspaceDescriptor()

        status = ce.cuestDFIntPlanCreateWorkspaceQuery(
            handle=handle.handle,
            primaryBasis=primary.ao_basis_handle,
            auxiliaryBasis=auxiliary.ao_basis_handle,
            pairList=ao_pair_list.ao_pair_list_handle,
            parameters=df_int_plan_parameters.parameters,
            persistentWorkspaceDescriptor=persistent_workspace_descriptor.pointer,
            temporaryWorkspaceDescriptor=temporary_workspace_descriptor.pointer,
            outPlan=self.df_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFIntPlanCreateWorkspaceQuery failed')

        # Most likely place to run out of device memory, so we will add a custom RuntimeError
        try:
            persistent_workspace = CuestWorkspace(workspaceDescriptor=persistent_workspace_descriptor)
            temporary_workspace = CuestWorkspace(workspaceDescriptor=temporary_workspace_descriptor)
        except RuntimeError as e:
            raise RuntimeError("CuestDFIntPlan workspace allocation failed - out of memory for CoreDF") from e

        # => Creation <= #

        status = ce.cuestDFIntPlanCreate(
            handle=handle.handle,
            primaryBasis=primary.ao_basis_handle,
            auxiliaryBasis=auxiliary.ao_basis_handle,
            pairList=ao_pair_list.ao_pair_list_handle,
            parameters=df_int_plan_parameters.parameters,
            persistentWorkspace=persistent_workspace.pointer,
            temporaryWorkspace=temporary_workspace.pointer,
            outPlan=self.df_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFIntPlanCreate failed')

        # Bind the lifetime of persistent_workspace to this object
        self.persistent_workspace = persistent_workspace

        self.initialized = True

    def __del__(self):

        if not self.initialized: return

        status = ce.cuestDFIntPlanDestroy(
            handle=self.df_int_plan_handle,
            )

        if status != ce.CuestStatus.CUEST_STATUS_SUCCESS:
            raise RuntimeError('cuestDFIntPlanDestroy failed')