/*
 * SPDX-License-Identifier: BSD-3-Clause
 * Copyright (c) 1996-2025, The SLICOT Team (original Fortran77 code)
 * Copyright (c) 2025, slicot.c contributors (C11 translation)
 */

#ifndef SLICOT_LAPACK_AUX_H
#define SLICOT_LAPACK_AUX_H

#include "../slicot_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @brief Apply a Householder matrix generated by DTZRQF to a matrix.
 *
 * This routine is deprecated and has been replaced by routine DORMRZ.
 *
 * DLATZM applies a Householder matrix generated by DTZRQF to a matrix.
 *
 * Let P = I - tau*u*u^T, where u = [1; v], and v is an (m-1) vector if
 * SIDE = 'L', or an (n-1) vector if SIDE = 'R'.
 *
 * If SIDE = 'L', the matrix C = [C1; C2] is overwritten by P*C.
 * If SIDE = 'R', the matrix C = [C1, C2] is overwritten by C*P.
 *
 * @param[in] side 'L' for left multiplication P*C, 'R' for right C*P
 * @param[in] m Number of rows of C
 * @param[in] n Number of columns of C
 * @param[in] v Vector in representation of P, dimension:
 *              (1 + (m-1)*|incv|) if SIDE='L'
 *              (1 + (n-1)*|incv|) if SIDE='R'
 * @param[in] incv Increment between elements of v (incv != 0)
 * @param[in] tau Scalar in representation of P
 * @param[in,out] c1 First row/column of C:
 *                   (ldc, n) if SIDE='L', (m, 1) if SIDE='R'
 * @param[in,out] c2 Remaining rows/columns of C:
 *                   (ldc, n) if SIDE='L', (ldc, n-1) if SIDE='R'
 * @param[in] ldc Leading dimension of C1 and C2 (ldc >= max(1, m))
 * @param[out] work Workspace, dimension (n) if SIDE='L', (m) if SIDE='R'
 */
void slicot_dlatzm(const char *side, i32 m, i32 n, const f64 *v, i32 incv,
                   f64 tau, f64 *c1, f64 *c2, i32 ldc, f64 *work);

/**
 * @brief Compute generalized eigenvalues and eigenvectors of a real matrix pair.
 *
 * This routine is deprecated and has been replaced by routine DGGEV.
 *
 * DGEGV computes the eigenvalues and, optionally, the left and/or right
 * eigenvectors of a real matrix pair (A,B). Given two square matrices A and B,
 * the generalized nonsymmetric eigenvalue problem (GNEP) is to find the
 * eigenvalues lambda and corresponding eigenvectors x such that A*x = lambda*B*x.
 *
 * The eigenvalues are returned as (ALPHAR(j) + i*ALPHAI(j)) / BETA(j) to handle
 * cases where lambda may be infinite (when BETA(j) = 0).
 *
 * @param[in] jobvl 'N': do not compute left eigenvectors,
 *                  'V': compute left eigenvectors
 * @param[in] jobvr 'N': do not compute right eigenvectors,
 *                  'V': compute right eigenvectors
 * @param[in] n The order of matrices A and B (n >= 0)
 * @param[in,out] a On entry, the matrix A (n x n).
 *                  On exit, overwritten with the real Schur form (if eigenvectors
 *                  are computed) or just the diagonal blocks otherwise.
 * @param[in] lda Leading dimension of A (lda >= max(1, n))
 * @param[in,out] b On entry, the matrix B (n x n).
 *                  On exit, overwritten with the upper triangular matrix from
 *                  the generalized Schur factorization.
 * @param[in] ldb Leading dimension of B (ldb >= max(1, n))
 * @param[out] alphar Real parts of the eigenvalue numerators, dimension (n)
 * @param[out] alphai Imaginary parts of the eigenvalue numerators, dimension (n)
 * @param[out] beta Denominators of eigenvalues, dimension (n)
 * @param[out] vl Left eigenvectors (n x n), if JOBVL = 'V'
 * @param[in] ldvl Leading dimension of VL (ldvl >= 1, or ldvl >= n if JOBVL = 'V')
 * @param[out] vr Right eigenvectors (n x n), if JOBVR = 'V'
 * @param[in] ldvr Leading dimension of VR (ldvr >= 1, or ldvr >= n if JOBVR = 'V')
 * @param[out] work Workspace array, dimension (max(1, lwork))
 * @param[in] lwork Size of work array (lwork >= max(1, 8*n)).
 *                  If lwork = -1, workspace query is performed.
 * @return info = 0: successful exit
 *         info < 0: if info = -i, the i-th argument had an illegal value
 *         info = 1,...,N: QZ iteration failed
 *         info > N: errors from LAPACK subroutines
 */
i32 slicot_dgegv(const char *jobvl, const char *jobvr, i32 n, f64 *a, i32 lda,
                 f64 *b, i32 ldb, f64 *alphar, f64 *alphai, f64 *beta,
                 f64 *vl, i32 ldvl, f64 *vr, i32 ldvr,
                 f64 *work, i32 lwork);

/**
 * @brief Compute generalized Schur form for complex matrix pair.
 *
 * This routine is deprecated and has been replaced by routine ZGGES.
 *
 * ZGEGS computes the eigenvalues, Schur form, and, optionally, the left and/or
 * right Schur vectors of a complex matrix pair (A,B). Given two square matrices
 * A and B, the generalized Schur factorization has the form:
 *
 *    A = Q*S*Z^H,  B = Q*T*Z^H
 *
 * where Q and Z are unitary matrices and S and T are upper triangular.
 * The columns of Q are the left Schur vectors.
 * The columns of Z are the right Schur vectors.
 *
 * @param[in] jobvsl 'N': do not compute left Schur vectors,
 *                   'V': compute left Schur vectors (returned in VSL)
 * @param[in] jobvsr 'N': do not compute right Schur vectors,
 *                   'V': compute right Schur vectors (returned in VSR)
 * @param[in] n The order of matrices A and B (n >= 0)
 * @param[in,out] a On entry, the matrix A (n x n).
 *                  On exit, the upper triangular matrix S from the
 *                  generalized Schur factorization.
 * @param[in] lda Leading dimension of A (lda >= max(1, n))
 * @param[in,out] b On entry, the matrix B (n x n).
 *                  On exit, the upper triangular matrix T from the
 *                  generalized Schur factorization.
 * @param[in] ldb Leading dimension of B (ldb >= max(1, n))
 * @param[out] alpha Complex scalars that define the eigenvalues.
 *                   ALPHA(j) = S(j,j), the diagonal element of the Schur form of A.
 * @param[out] beta Complex scalars that define the eigenvalues.
 *                  BETA(j) = T(j,j), the diagonal element of the triangular factor T.
 *                  Together, alpha(j)/beta(j) represents the j-th eigenvalue.
 * @param[out] vsl Left Schur vectors (n x n), if JOBVSL = 'V'
 * @param[in] ldvsl Leading dimension of VSL (ldvsl >= 1, or ldvsl >= n if JOBVSL = 'V')
 * @param[out] vsr Right Schur vectors (n x n), if JOBVSR = 'V'
 * @param[in] ldvsr Leading dimension of VSR (ldvsr >= 1, or ldvsr >= n if JOBVSR = 'V')
 * @param[out] work Complex workspace array, dimension (max(1, lwork))
 * @param[in] lwork Size of work array (lwork >= max(1, 2*n)).
 *                  If lwork = -1, workspace query is performed.
 * @param[out] rwork Real workspace array, dimension (3*n)
 * @return info = 0: successful exit
 *         info < 0: if info = -i, the i-th argument had an illegal value
 *         info = 1,...,N: QZ iteration failed
 *         info > N: errors from LAPACK subroutines
 */
i32 slicot_zgegs(const char *jobvsl, const char *jobvsr, i32 n, c128 *a, i32 lda,
                 c128 *b, i32 ldb, c128 *alpha, c128 *beta,
                 c128 *vsl, i32 ldvsl, c128 *vsr, i32 ldvsr,
                 c128 *work, i32 lwork, f64 *rwork);

/**
 * @brief Compute generalized eigenvalues and eigenvectors of complex matrix pair.
 *
 * This routine is deprecated and has been replaced by routine ZGGEV.
 *
 * ZGEGV computes the eigenvalues and, optionally, the left and/or right
 * eigenvectors of a complex matrix pair (A,B). Given two square matrices A and B,
 * the generalized nonsymmetric eigenvalue problem (GNEP) is to find the
 * eigenvalues lambda and corresponding eigenvectors x such that A*x = lambda*B*x.
 *
 * The eigenvalues are returned as ALPHA(j) / BETA(j) to handle
 * cases where lambda may be infinite (when BETA(j) = 0).
 *
 * @param[in] jobvl 'N': do not compute left eigenvectors,
 *                  'V': compute left eigenvectors
 * @param[in] jobvr 'N': do not compute right eigenvectors,
 *                  'V': compute right eigenvectors
 * @param[in] n The order of matrices A and B (n >= 0)
 * @param[in,out] a On entry, the matrix A (n x n).
 *                  On exit, overwritten with the complex Schur form (if eigenvectors
 *                  are computed) or just the diagonal elements otherwise.
 * @param[in] lda Leading dimension of A (lda >= max(1, n))
 * @param[in,out] b On entry, the matrix B (n x n).
 *                  On exit, overwritten with the upper triangular matrix from
 *                  the generalized Schur factorization.
 * @param[in] ldb Leading dimension of B (ldb >= max(1, n))
 * @param[out] alpha Complex eigenvalue numerators, dimension (n)
 * @param[out] beta Complex eigenvalue denominators, dimension (n)
 * @param[out] vl Left eigenvectors (n x n), if JOBVL = 'V'
 * @param[in] ldvl Leading dimension of VL (ldvl >= 1, or ldvl >= n if JOBVL = 'V')
 * @param[out] vr Right eigenvectors (n x n), if JOBVR = 'V'
 * @param[in] ldvr Leading dimension of VR (ldvr >= 1, or ldvr >= n if JOBVR = 'V')
 * @param[out] work Complex workspace array, dimension (max(1, lwork))
 * @param[in] lwork Size of work array (lwork >= max(1, 2*n)).
 *                  If lwork = -1, workspace query is performed.
 * @param[out] rwork Real workspace array, dimension (8*n)
 * @return info = 0: successful exit
 *         info < 0: if info = -i, the i-th argument had an illegal value
 *         info = 1,...,N: QZ iteration failed
 *         info > N: errors from LAPACK subroutines
 */
i32 slicot_zgegv(const char *jobvl, const char *jobvr, i32 n, c128 *a, i32 lda,
                 c128 *b, i32 ldb, c128 *alpha, c128 *beta,
                 c128 *vl, i32 ldvl, c128 *vr, i32 ldvr,
                 c128 *work, i32 lwork, f64 *rwork);

#ifdef __cplusplus
}
#endif

#endif /* SLICOT_LAPACK_AUX_H */
