/**
 *
 * @file order_add_isolate.c
 *
 * PaStiX order routines to add subset of isolated vertices.
 *
 * @copyright 2004-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 * @version 6.4.0
 * @author Xavier Lacoste
 * @author Mathieu Faverge
 * @author Pierre Ramet
 * @date 2024-07-05
 *
 **/
#include "common.h"
#include "order/order_internal.h"

/**
 *******************************************************************************
 *
 * @ingroup pastix_order
 *
 * @brief This routine combines two permutation arrays when a subset
 * of vertices has been isolated from the original graph through graphIsolate()
 * function.
 *
 *******************************************************************************
 *
 * @param[inout] ordemesh
 *          The ordering generated by the ordering tool.
 *
 * @param[in] new_n
 *          The total number of vertices in the combined graph
 *
 * @param[in] perm
 *          Array of size new_n that must be 0-based.
 *          The permutation array that isolated the extra vertices at the end of
 *          the graph. This permutation will be combined with the one stored in
 *          ordemesh to generate a permutation array for the full graph.
 *          This permutation must be 0-based.
 *
 *******************************************************************************
 *
 * @retval PASTIX_SUCCESS on successful exit,
 * @retval PASTIX_ERR_BADPARAMETER if one parameter is incorrect,
 * @retval PASTIX_ERR_OUTOFMEMORY if one allocation failed.
 *
 *******************************************************************************
 *
 * @sa graphIsolate
 *
 *******************************************************************************/
int
orderAddIsolate(       pastix_order_t *ordemesh,
                       pastix_int_t    new_n,
                 const pastix_int_t   *perm )
{
    pastix_order_t ordesave;
    pastix_int_t i, ip;
    pastix_int_t n;
    pastix_int_t cblknbr;
    int baseval, rc;

    /* Parameter checks */
    if ( ordemesh == NULL ) {
        return PASTIX_ERR_BADPARAMETER;
    }
    if ( new_n < ordemesh->vertnbr ) {
        return PASTIX_ERR_BADPARAMETER;
    }
    if ( perm == NULL ) {
        return PASTIX_ERR_BADPARAMETER;
    }

    n       = ordemesh->vertnbr;
    cblknbr = ordemesh->cblknbr;
    baseval = ordemesh->baseval;

    /* Quick return */
    if ( n == new_n )
        return PASTIX_SUCCESS;

    assert( n <= new_n );

    memcpy( &ordesave, ordemesh, sizeof(pastix_order_t) );
    rc = pastixOrderAlloc( ordemesh, new_n, cblknbr + 1 );
    if (rc != PASTIX_SUCCESS) {
        return rc;
    }

    ordemesh->baseval = baseval;
    for(i=0; i< new_n; i++) {
        ip = perm[i];
        assert(ip < new_n);
        if (ip < n) {
            ordemesh->permtab[i] = ordesave.permtab[ ip ];
        }
        else {
            ordemesh->permtab[i] = ip+baseval;
        }
    }
    for(i=0; i<new_n; i++) {
        ip = ordemesh->permtab[i] - baseval;
        assert( (ip > -1) && (ip < new_n) );
        ordemesh->peritab[ip] = i + baseval;
    }

    /* Copy the cblknbr+1 first element of old rangtab and add last element */
    assert( ordesave.rangtab != NULL );
    memcpy( ordemesh->rangtab, ordesave.rangtab, (ordesave.cblknbr+1) * sizeof(pastix_int_t) );
    ordemesh->rangtab[ ordemesh->cblknbr ] = new_n + baseval;

    /* We connect each roots of the elimination forest to the new cblk (shur or isolated terms) */
    assert( ordesave.treetab != NULL );
    memcpy( ordemesh->treetab, ordesave.treetab, ordesave.cblknbr * sizeof(pastix_int_t) );
    for(i=0; i < ordesave.cblknbr; i++)  {
        assert( ordemesh->treetab[i] != i );
        /* This was a root, we connect it to the last one */
        if ( ordemesh->treetab[i] == -1 ) {
            ordemesh->treetab[ i ] = ordesave.cblknbr + baseval;
        }
    }
    ordemesh->treetab[ ordesave.cblknbr ] = -1;

    pastixOrderExit( &ordesave );
    return PASTIX_SUCCESS;
}

