//------------------------------------------------------------------------------
// CHOLMOD/Partition/cholmod_csymamd: CHOLMOD interface to CSYMAMD
//------------------------------------------------------------------------------

// CHOLMOD/Partition Module.  Copyright (C) 2005-2023, University of Florida.
// All Rights Reserved.  Author: Timothy A. Davis.
// SPDX-License-Identifier: LGPL-2.1+

//------------------------------------------------------------------------------

// CHOLMOD interface to the CSYMAMD ordering routine.  Finds a permutation
// p such that the Cholesky factorization of PAP' is sparser than A.
// The column etree is found and postordered, and the CSYMAMD
// ordering is then combined with its postordering.  If A is unsymmetric,
// A+A' is ordered (A must be square).
//
// workspace: Head (nrow+1)
//
// Supports any xtype (pattern, real, complex, or zomplex) and any dtype.

#include "cholmod_internal.h"

#ifndef NCAMD

#include "ccolamd.h"
#if (CCOLAMD_VERSION < CCOLAMD_VERSION_CODE (3,3))
#error "CHOLMOD:Partition requires CCOLAMD 3.3.1 or later"
#endif

//------------------------------------------------------------------------------
// cholmod_csymamd
//------------------------------------------------------------------------------

int CHOLMOD(csymamd)
(
    // input:
    cholmod_sparse *A,  // matrix to order
    // output:
    Int *Cmember,       // size nrow.  see cholmod_ccolamd.c for description
    Int *Perm,          // size A->nrow, output permutation
    cholmod_common *Common
)
{

    //--------------------------------------------------------------------------
    // check inputs
    //--------------------------------------------------------------------------

    double knobs [CCOLAMD_KNOBS] ;
    Int *perm, *Head ;
    Int ok, i, nrow, stats [CCOLAMD_STATS] ;

    RETURN_IF_NULL_COMMON (FALSE) ;
    RETURN_IF_NULL (A, FALSE) ;
    RETURN_IF_NULL (Perm, FALSE) ;
    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
    Common->status = CHOLMOD_OK ;

    if (A->nrow != A->ncol || !(A->packed))
    {
        ERROR (CHOLMOD_INVALID, "matrix must be square and packed") ;
        return (FALSE) ;
    }

    //--------------------------------------------------------------------------
    // get inputs
    //--------------------------------------------------------------------------

    nrow = A->nrow ;

    //--------------------------------------------------------------------------
    // allocate workspace
    //--------------------------------------------------------------------------

    CHOLMOD(allocate_work) (nrow, 0, 0, Common) ;
    if (Common->status < CHOLMOD_OK)
    {
        return (FALSE) ;
    }

    //--------------------------------------------------------------------------
    // order the matrix (does not affect A->p or A->i)
    //--------------------------------------------------------------------------

    perm = Common->Head ;       // size nrow+1

    // get parameters
#if defined ( CHOLMOD_INT64 )
    ccolamd_l_set_defaults (knobs) ;
#else
    ccolamd_set_defaults (knobs) ;
#endif
    if (Common->current >= 0 && Common->current < CHOLMOD_MAXMETHODS)
    {
        // get the knobs from the Common parameters
        knobs [CCOLAMD_DENSE_ROW] =Common->method[Common->current].prune_dense ;
        knobs [CCOLAMD_AGGRESSIVE]=Common->method[Common->current].aggressive ;
    }
    {
        void * (*calloc_func) (size_t, size_t) ;
        void (*free_func) (void *) ;
        calloc_func = SuiteSparse_config_calloc_func_get ( ) ;
        free_func   = SuiteSparse_config_free_func_get ( ) ;

#if defined ( CHOLMOD_INT64 )
        csymamd_l (nrow, A->i, A->p, perm, knobs, stats,
                calloc_func,
                free_func,
                Cmember, A->stype) ;
#else
        csymamd (nrow, A->i, A->p, perm, knobs, stats,
                calloc_func,
                free_func,
                Cmember, A->stype) ;
#endif
        ok = stats [CCOLAMD_STATUS] ;
    }

    if (ok == CCOLAMD_ERROR_out_of_memory)
    {
        ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ;
    }
    ok = (ok == CCOLAMD_OK || ok == CCOLAMD_OK_BUT_JUMBLED) ;

    //--------------------------------------------------------------------------
    // free the workspace and return result
    //--------------------------------------------------------------------------

    // permutation returned in perm [0..n-1]
    for (i = 0 ; i < nrow ; i++)
    {
        Perm [i] = perm [i] ;
    }

    // clear Head workspace (used for perm, in csymamd):
    Head = Common->Head ;
    for (i = 0 ; i <= nrow ; i++)
    {
        Head [i] = EMPTY ;
    }

    return (ok) ;
}

#endif

