Skip to content

File mut_rlitt_ringshift.c

File List > mut-rlitt_ringshift > src > mut_rlitt_ringshift.c

Go to the documentation of this file

/******************************************************************************/
/************************** Includes ******************************************/
/******************************************************************************/

#include "mut_rlitt_ringshift.h"
#include "stdbool.h"
#include "stdint.h"
#include "stdio.h"
#include "stdlib.h"
#include "tang_defs.h"

/******************************************************************************/
/************************** Defines *******************************************/
/******************************************************************************/

#define MUT_RLITT_RINGSHIFT_STACK_SIZE    (UTIL_TANG_DEFS_MAX_CROSSINGNUM)

/******************************************************************************/
/************************** Typedefs ******************************************/
/******************************************************************************/

/******************************************************************************/
/************************** Private Function Declarations *********************/
/******************************************************************************/
STATIC_INLINE bool mut_rlitt_ringshift_is_ringsubtree(const note_wptt_node_t *node);
STATIC_INLINE int mut_rlitt_ringshift_ringsubtreecmp(const void *node1,
                                                     const void *node2);
STATIC_INLINE void mut_rlitt_ringshift_move_ringsubtrees(note_wptt_node_t *node);
STATIC_INLINE_UINT8 mut_rlitt_ringshift_ringshift_tree(note_wptt_t *tree);

/******************************************************************************/
/************************** Local Variables ***********************************/
/******************************************************************************/

static note_wptt_node_t *mut_rlitt_ringshift_localnodes;

static mut_rlitt_ringshift_config_t *mut_rlitt_ringshift_localcfg = NULL;

static bool mut_rlitt_ringshift_executed = false;
/******************************************************************************/
/************************** Public Function Definitions ***********************/
/******************************************************************************/

/*
 *  Documentation in header
 */
uint8_t mut_rlitt_ringshift_config(mut_rlitt_ringshift_config_t *config_arg)
{
    uint8_t ret_val = MUT_DEFS_CONFIG_FAIL;

    mut_rlitt_ringshift_localcfg = NULL;

    /*Ensure the cfg is not empty.*/
    if (config_arg == NULL)
    {
        ret_val |= MUT_RLITT_RINGSHIFT_CONFIG_IS_NULL;
    } /*Ensure the wptt is not empty.*/
    else if (config_arg->wptt == NULL)
    {
        ret_val |= MUT_RLITT_RINGSHIFT_CONFIG_WPTT;
    }
    else
    {
        /* Set the config. */
        mut_rlitt_ringshift_localcfg = config_arg;


        /*clear the executed status*/
        mut_rlitt_ringshift_executed = false;

        ret_val = MUT_DEFS_CONFIG_SUCCESS;
    }
    return ret_val;
}

/*
 *  Documentation in header
 */
uint8_t mut_rlitt_ringshift_mutate()
{
    uint8_t ret_val = MUT_DEFS_MUTATE_FAIL;

    /*Ensure the cfg is not empty.*/
    if (mut_rlitt_ringshift_localcfg == NULL)
    {
        ret_val |= MUT_RLITT_RINGSHIFT_MUTATE_CFG_ERROR;
    } /*Ensure not previously executed.*/
    else if (mut_rlitt_ringshift_executed != false)
    {
        ret_val |= MUT_RLITT_RINGSHIFT_MUTATE_ALREADY_COMPUTED;
    }
    else
    {
        ret_val = MUT_DEFS_MUTATE_SUCCESS;
        mut_rlitt_ringshift_executed = true;
        ret_val |= mut_rlitt_ringshift_ringshift_tree(mut_rlitt_ringshift_localcfg->wptt);
    }
    return ret_val;
}

/******************************************************************************/
/************************** Private Function Declarations *********************/
/******************************************************************************/

STATIC_INLINE_UINT8 mut_rlitt_ringshift_ringshift_tree(note_wptt_t *tree)
{
    uint8_t           ret_val = MUT_DEFS_MUTATE_SUCCESS;
    note_wptt_node_t *stack[MUT_RLITT_RINGSHIFT_STACK_SIZE]          = { NULL };
    size_t            childidx_stack[MUT_RLITT_RINGSHIFT_STACK_SIZE] = { 0 };

    /* We are going to use count instead of index. This helps with intuiting the state of the stack.
     * The count starts at 1 since the root is going to be added to the stack before the main loop.
     */
    size_t stack_count = 1;

    /* try to shift the root */
    mut_rlitt_ringshift_move_ringsubtrees(tree->root);

    stack[stack_count - 1] = tree->root;
    while (stack_count != 0)
    {
        note_wptt_node_t *active_node_p = stack[stack_count - 1];
        if (active_node_p->number_of_children <= childidx_stack[stack_count - 1])
        {
            /* shift the active vertex. */
            mut_rlitt_ringshift_move_ringsubtrees(active_node_p);
            stack_count--;
        }
        else
        {
            size_t child_idx = childidx_stack[stack_count - 1];
            /*Push child to stack*/
            childidx_stack[stack_count - 1]++;
            stack_count++;
            stack[stack_count - 1]          = active_node_p->children[child_idx];
            childidx_stack[stack_count - 1] = 0;
        }
    }

    return ret_val;
}

STATIC_INLINE void mut_rlitt_ringshift_reverse_node(note_wptt_node_t *node)
{
    size_t i = 0;

    for (i = 0; 2 * i < node->number_of_children; i++)
    {
        size_t            back_child_pos  = (node->number_of_children - 1) - i;
        size_t            back_weight_pos = node->number_of_children - i;
        note_wptt_node_t *child           = node->children[i];
        uint8_t           weight          = node->weights[i];

        node->children[i] = node->children[back_child_pos];
        node->children[back_child_pos] = child;

        node->weights[i] = node->weights[back_weight_pos];
        node->weights[back_weight_pos] = weight;
    }
    if (node->order == NOTE_WPTT_ORDER_REVERSE)
    {
        node->order = NOTE_WPTT_ORDER_FORWARD;
    }
    else
    {
        node->order = NOTE_WPTT_ORDER_REVERSE;
    }
}

STATIC_INLINE bool mut_rlitt_ringshift_is_ringsubtree(const note_wptt_node_t *node)
{
    bool ret_val = false;

    if (node->number_of_children == 2)
    {
        if ((node->weights[node->number_of_children] == 1) &&
            (node->children[0]->number_of_children == 0) &&
            (node->children[0]->weights[0] == 2) &&
            (node->children[1]->number_of_children == 0) &&
            (node->children[1]->weights[0] == 2))
        {
            ret_val = true;
        }
        if ((node->weights[node->number_of_children] == -1) &&
            (node->children[0]->number_of_children == 0) &&
            (node->children[0]->weights[0] == -2) &&
            (node->children[1]->number_of_children == 0) &&
            (node->children[1]->weights[0] == -2))
        {
            ret_val = true;
        }
    }
    return ret_val;
}

STATIC_INLINE int mut_rlitt_ringshift_ringsubtreecmp(const void *node1, const void *node2)
{
    bool node1_ring = mut_rlitt_ringshift_is_ringsubtree(
        *(const note_wptt_node_t **)node1);
    bool node2_ring = mut_rlitt_ringshift_is_ringsubtree(
        *(const note_wptt_node_t **)node2);

    if (node1_ring != node2_ring)
    {
        if (true == node1_ring)
        {
            return 1;
        }
        return -1;
    }
    return 0;
}

STATIC_INLINE void mut_rlitt_ringshift_move_ringsubtrees(note_wptt_node_t *node)
{
    if (node->number_of_children != 0)
    {
        /* Sort the children of the input vertex. The qsort function swaps in place based on the
         * given compare function. */
        qsort(node->children,
              node->number_of_children,
              sizeof(note_wptt_node_t *),
              mut_rlitt_ringshift_ringsubtreecmp);
    }
}