//------------------------------------------------------------------------------
// GB_binop_rename: rename a bound binary operator to its unary op equivalent
//------------------------------------------------------------------------------

// SuiteSparse:GraphBLAS, Timothy A. Davis, (c) 2017-2022, All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

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

// A binary operator can be applied to a matrix with GrB_apply, but some of
// them can be remapped into equivalent unary operators.  Any idxunop can also
// be applied, and some of them can be remapped into binary ops (with bind2nd).

#include "GB.h"
#include "GB_binop.h"

void GB_binop_rename            // rename a bound binary op or an idxunop
(
    GB_Operator *op,            // operator to rename
    bool binop_bind1st
)
{

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

    ASSERT (op != NULL && (*op) != NULL) ;
    GB_Opcode opcode = (*op)->opcode ;
    GrB_Type xtype = (*op)->xtype ;
    GB_Type_code xcode = (xtype == NULL) ? GB_ignore_code : xtype->code ;

    //--------------------------------------------------------------------------
    // rename a binary op or an idxunop
    //--------------------------------------------------------------------------

    if (GB_IS_BINARYOP_CODE (opcode))
    {

        //----------------------------------------------------------------------
        // rename a binary operator to its equivalent unary op
        //----------------------------------------------------------------------

        if (xcode == GB_BOOL_code)
        { 
            // for boolean: DIV becomes FIRST, RDIV becomes SECOND
            opcode = GB_boolean_rename (opcode) ;
        }

        if ((opcode == GB_FIRST_binop_code  && !binop_bind1st) ||
            (opcode == GB_SECOND_binop_code &&  binop_bind1st))
        { 

            //------------------------------------------------------------------
            // first(A,scalar) and second(scalar,A) become identity(A)
            //------------------------------------------------------------------

            switch (xcode)
            {
                case GB_BOOL_code    : (*op) = (GB_Operator) GrB_IDENTITY_BOOL   ; break ;
                case GB_INT8_code    : (*op) = (GB_Operator) GrB_IDENTITY_INT8   ; break ;
                case GB_INT16_code   : (*op) = (GB_Operator) GrB_IDENTITY_INT16  ; break ;
                case GB_INT32_code   : (*op) = (GB_Operator) GrB_IDENTITY_INT32  ; break ;
                case GB_INT64_code   : (*op) = (GB_Operator) GrB_IDENTITY_INT64  ; break ;
                case GB_UINT8_code   : (*op) = (GB_Operator) GrB_IDENTITY_UINT8  ; break ;
                case GB_UINT16_code  : (*op) = (GB_Operator) GrB_IDENTITY_UINT16 ; break ;
                case GB_UINT32_code  : (*op) = (GB_Operator) GrB_IDENTITY_UINT32 ; break ;
                case GB_UINT64_code  : (*op) = (GB_Operator) GrB_IDENTITY_UINT64 ; break ;
                case GB_FP32_code    : (*op) = (GB_Operator) GrB_IDENTITY_FP32   ; break ;
                case GB_FP64_code    : (*op) = (GB_Operator) GrB_IDENTITY_FP64   ; break ;
                case GB_FC32_code    : (*op) = (GB_Operator) GxB_IDENTITY_FC32   ; break ;
                case GB_FC64_code    : (*op) = (GB_Operator) GxB_IDENTITY_FC64   ; break ;
                default:;
            }

        }
        else if (opcode == GB_PAIR_binop_code)
        { 

            //------------------------------------------------------------------
            // pair(A,scalar) and pair(scalar,A) become one(A)
            //------------------------------------------------------------------

            (*op) = (GB_Operator) GB_unop_one (xcode) ;
        }

    }
    else if (GB_IS_INDEXUNARYOP_CODE (opcode))
    {

        //----------------------------------------------------------------------
        // rename an idxunop operator to its equivalent binary op
        //----------------------------------------------------------------------

        // All built-in GrB_IndexUnaryOps of the form GrB_VALUE* can be
        // remapped to equivalent binary ops, with bind 2nd.  After this
        // remapping, only the positional idxunops need to be handled in
        // GB_apply, as well as user-defined idxunops.

        ASSERT (!binop_bind1st) ;

        switch (opcode)
        {
            case GB_VALUENE_idxunop_code : // (aij != thunk)

                switch (xcode)
                {
                    case GB_BOOL_code    : (*op) = (GB_Operator) GrB_NE_BOOL   ; break ;
                    case GB_INT8_code    : (*op) = (GB_Operator) GrB_NE_INT8   ; break ;
                    case GB_INT16_code   : (*op) = (GB_Operator) GrB_NE_INT16  ; break ;
                    case GB_INT32_code   : (*op) = (GB_Operator) GrB_NE_INT32  ; break ;
                    case GB_INT64_code   : (*op) = (GB_Operator) GrB_NE_INT64  ; break ;
                    case GB_UINT8_code   : (*op) = (GB_Operator) GrB_NE_UINT8  ; break ;
                    case GB_UINT16_code  : (*op) = (GB_Operator) GrB_NE_UINT16 ; break ;
                    case GB_UINT32_code  : (*op) = (GB_Operator) GrB_NE_UINT32 ; break ;
                    case GB_UINT64_code  : (*op) = (GB_Operator) GrB_NE_UINT64 ; break ;
                    case GB_FP32_code    : (*op) = (GB_Operator) GrB_NE_FP32   ; break ;
                    case GB_FP64_code    : (*op) = (GB_Operator) GrB_NE_FP64   ; break ;
                    case GB_FC32_code    : (*op) = (GB_Operator) GxB_NE_FC32   ; break ;
                    case GB_FC64_code    : (*op) = (GB_Operator) GxB_NE_FC64   ; break ;
                    default:;
                }
                break ;

            case GB_VALUEEQ_idxunop_code : // (aij == thunk)

                switch (xcode)
                {
                    case GB_BOOL_code    : (*op) = (GB_Operator) GrB_EQ_BOOL   ; break ;
                    case GB_INT8_code    : (*op) = (GB_Operator) GrB_EQ_INT8   ; break ;
                    case GB_INT16_code   : (*op) = (GB_Operator) GrB_EQ_INT16  ; break ;
                    case GB_INT32_code   : (*op) = (GB_Operator) GrB_EQ_INT32  ; break ;
                    case GB_INT64_code   : (*op) = (GB_Operator) GrB_EQ_INT64  ; break ;
                    case GB_UINT8_code   : (*op) = (GB_Operator) GrB_EQ_UINT8  ; break ;
                    case GB_UINT16_code  : (*op) = (GB_Operator) GrB_EQ_UINT16 ; break ;
                    case GB_UINT32_code  : (*op) = (GB_Operator) GrB_EQ_UINT32 ; break ;
                    case GB_UINT64_code  : (*op) = (GB_Operator) GrB_EQ_UINT64 ; break ;
                    case GB_FP32_code    : (*op) = (GB_Operator) GrB_EQ_FP32   ; break ;
                    case GB_FP64_code    : (*op) = (GB_Operator) GrB_EQ_FP64   ; break ;
                    case GB_FC32_code    : (*op) = (GB_Operator) GxB_EQ_FC32   ; break ;
                    case GB_FC64_code    : (*op) = (GB_Operator) GxB_EQ_FC64   ; break ;
                    default:;
                }
                break ;

            case GB_VALUEGT_idxunop_code : // (aij > thunk)

                switch (xcode)
                {
                    case GB_BOOL_code    : (*op) = (GB_Operator) GrB_GT_BOOL   ; break ;
                    case GB_INT8_code    : (*op) = (GB_Operator) GrB_GT_INT8   ; break ;
                    case GB_INT16_code   : (*op) = (GB_Operator) GrB_GT_INT16  ; break ;
                    case GB_INT32_code   : (*op) = (GB_Operator) GrB_GT_INT32  ; break ;
                    case GB_INT64_code   : (*op) = (GB_Operator) GrB_GT_INT64  ; break ;
                    case GB_UINT8_code   : (*op) = (GB_Operator) GrB_GT_UINT8  ; break ;
                    case GB_UINT16_code  : (*op) = (GB_Operator) GrB_GT_UINT16 ; break ;
                    case GB_UINT32_code  : (*op) = (GB_Operator) GrB_GT_UINT32 ; break ;
                    case GB_UINT64_code  : (*op) = (GB_Operator) GrB_GT_UINT64 ; break ;
                    case GB_FP32_code    : (*op) = (GB_Operator) GrB_GT_FP32   ; break ;
                    case GB_FP64_code    : (*op) = (GB_Operator) GrB_GT_FP64   ; break ;
                    default:;
                }
                break ;

            case GB_VALUEGE_idxunop_code : // (aij >= thunk)

                switch (xcode)
                {
                    case GB_BOOL_code    : (*op) = (GB_Operator) GrB_GE_BOOL   ; break ;
                    case GB_INT8_code    : (*op) = (GB_Operator) GrB_GE_INT8   ; break ;
                    case GB_INT16_code   : (*op) = (GB_Operator) GrB_GE_INT16  ; break ;
                    case GB_INT32_code   : (*op) = (GB_Operator) GrB_GE_INT32  ; break ;
                    case GB_INT64_code   : (*op) = (GB_Operator) GrB_GE_INT64  ; break ;
                    case GB_UINT8_code   : (*op) = (GB_Operator) GrB_GE_UINT8  ; break ;
                    case GB_UINT16_code  : (*op) = (GB_Operator) GrB_GE_UINT16 ; break ;
                    case GB_UINT32_code  : (*op) = (GB_Operator) GrB_GE_UINT32 ; break ;
                    case GB_UINT64_code  : (*op) = (GB_Operator) GrB_GE_UINT64 ; break ;
                    case GB_FP32_code    : (*op) = (GB_Operator) GrB_GE_FP32   ; break ;
                    case GB_FP64_code    : (*op) = (GB_Operator) GrB_GE_FP64   ; break ;
                    default:;
                }
                break ;

            case GB_VALUELT_idxunop_code : // (aij < thunk)

                switch (xcode)
                {
                    case GB_BOOL_code    : (*op) = (GB_Operator) GrB_LT_BOOL   ; break ;
                    case GB_INT8_code    : (*op) = (GB_Operator) GrB_LT_INT8   ; break ;
                    case GB_INT16_code   : (*op) = (GB_Operator) GrB_LT_INT16  ; break ;
                    case GB_INT32_code   : (*op) = (GB_Operator) GrB_LT_INT32  ; break ;
                    case GB_INT64_code   : (*op) = (GB_Operator) GrB_LT_INT64  ; break ;
                    case GB_UINT8_code   : (*op) = (GB_Operator) GrB_LT_UINT8  ; break ;
                    case GB_UINT16_code  : (*op) = (GB_Operator) GrB_LT_UINT16 ; break ;
                    case GB_UINT32_code  : (*op) = (GB_Operator) GrB_LT_UINT32 ; break ;
                    case GB_UINT64_code  : (*op) = (GB_Operator) GrB_LT_UINT64 ; break ;
                    case GB_FP32_code    : (*op) = (GB_Operator) GrB_LT_FP32   ; break ;
                    case GB_FP64_code    : (*op) = (GB_Operator) GrB_LT_FP64   ; break ;
                    default:;
                }
                break ;

            case GB_VALUELE_idxunop_code : // (aij <= thunk)

                switch (xcode)
                {
                    case GB_BOOL_code    : (*op) = (GB_Operator) GrB_LE_BOOL   ; break ;
                    case GB_INT8_code    : (*op) = (GB_Operator) GrB_LE_INT8   ; break ;
                    case GB_INT16_code   : (*op) = (GB_Operator) GrB_LE_INT16  ; break ;
                    case GB_INT32_code   : (*op) = (GB_Operator) GrB_LE_INT32  ; break ;
                    case GB_INT64_code   : (*op) = (GB_Operator) GrB_LE_INT64  ; break ;
                    case GB_UINT8_code   : (*op) = (GB_Operator) GrB_LE_UINT8  ; break ;
                    case GB_UINT16_code  : (*op) = (GB_Operator) GrB_LE_UINT16 ; break ;
                    case GB_UINT32_code  : (*op) = (GB_Operator) GrB_LE_UINT32 ; break ;
                    case GB_UINT64_code  : (*op) = (GB_Operator) GrB_LE_UINT64 ; break ;
                    case GB_FP32_code    : (*op) = (GB_Operator) GrB_LE_FP32   ; break ;
                    case GB_FP64_code    : (*op) = (GB_Operator) GrB_LE_FP64   ; break ;
                    default:;
                }
                break ;

            default:;
        }
    }
}

