/*
 * The char * returned is malloc()ed and should be free()ed.
 */
DLLEXPORT int fc_solve_user_INTERNAL_calc_derived_states_wrapper(
        enum fcs_dbm_variant_type_t local_variant,
        const char * init_state_str_proto,
        int * const num_out_derived_states,
        fcs_derived_state_debug_t * * out_derived_states,
        const fcs_bool_t perform_horne_prune
        )
{
    fcs_state_keyval_pair_t init_state;
    fc_solve_delta_stater_t * delta;
    fcs_encoded_state_buffer_t enc_state;
    fcs_state_locs_struct_t locs;
    fcs_derived_state_t * derived_list = NULL;
    fcs_derived_state_t * derived_list_recycle_bin = NULL;
    fcs_compact_allocator_t allocator;
    fcs_meta_compact_allocator_t meta_alloc;
    int states_count = 0;
    fcs_derived_state_t * iter;
    fcs_derived_state_debug_t * debug_ret;
    int idx = 0;

    DECLARE_IND_BUF_T(indirect_stacks_buffer)

    fc_solve_initial_user_state_to_c(
            init_state_str_proto,
            &init_state,
            FREECELLS_NUM,
            STACKS_NUM,
            DECKS_NUM,
            indirect_stacks_buffer
            );

    delta = fc_solve_delta_stater_alloc(
            &(init_state.s),
            STACKS_NUM,
            FREECELLS_NUM
#ifndef FCS_FREECELL_ONLY
            , FCS_SEQ_BUILT_BY_ALTERNATE_COLOR
#endif
            );

    fcs_init_and_encode_state(
        delta,
        local_variant,
        &(init_state),
        &enc_state
        );

    fc_solve_meta_compact_allocator_init (&meta_alloc);
    fc_solve_compact_allocator_init( &allocator, &meta_alloc);

    instance_solver_thread_calc_derived_states(
        local_variant,
        &init_state,
        NULL,
        &derived_list,
        &derived_list_recycle_bin,
        &allocator,
        perform_horne_prune
    );


    iter = derived_list;

    while (iter)
    {
        states_count++;
        iter = iter->next;
    }

    *(num_out_derived_states) = states_count;


    debug_ret = SMALLOC(debug_ret, states_count);

    *(out_derived_states) = debug_ret;

    fc_solve_init_locs(&locs);

    iter = derived_list;
    while (iter)
    {
        debug_ret[idx].state_string =
        fc_solve_state_as_string(
            &(iter->state.s),
            &locs,
            FREECELLS_NUM,
            STACKS_NUM,
            DECKS_NUM,
            1,
            0,
            1
            );
        debug_ret[idx].move = iter->move;
        debug_ret[idx].core_irreversible_moves_count
            = iter->core_irreversible_moves_count;
        debug_ret[idx].num_non_reversible_moves_including_prune
            = iter->num_non_reversible_moves_including_prune;
        /* TODO : Put something meaningful there by passing it to the function. */
        debug_ret[idx].which_irreversible_moves_bitmask =
            iter->which_irreversible_moves_bitmask;
        idx++;
        iter = iter->next;
    }

    assert(idx == states_count);

    fc_solve_compact_allocator_finish(&allocator);
    fc_solve_meta_compact_allocator_finish( &meta_alloc );

    fc_solve_delta_stater_free (delta);

    return 0;
}
Beispiel #2
0
/*
 * The char * returned is malloc()ed and should be free()ed.
 */
DLLEXPORT int fc_solve_user_INTERNAL_calc_derived_states_wrapper(
    fcs_dbm_variant_type_t local_variant, const char *init_state_str_proto,
    int *const num_out_derived_states,
    fcs_derived_state_debug_t **out_derived_states,
    const fcs_bool_t perform_horne_prune)
{
    fcs_state_keyval_pair_t init_state;
    fcs_encoded_state_buffer_t enc_state;
    fcs_state_locs_struct_t locs;
    fcs_derived_state_t *derived_list = NULL;
    fcs_derived_state_t *derived_list_recycle_bin = NULL;
    fcs_compact_allocator_t allocator;
    fcs_meta_compact_allocator_t meta_alloc;
    size_t states_count = 0;
    fcs_derived_state_t *iter;
    DECLARE_IND_BUF_T(indirect_stacks_buffer)

    fc_solve_initial_user_state_to_c(init_state_str_proto, &init_state,
        FREECELLS_NUM, STACKS_NUM, DECKS_NUM, indirect_stacks_buffer);

    fc_solve_delta_stater_t delta;
    fc_solve_delta_stater_init(
        &delta, &(init_state.s), STACKS_NUM, FREECELLS_NUM
#ifndef FCS_FREECELL_ONLY
        ,
        FCS_SEQ_BUILT_BY_ALTERNATE_COLOR
#endif
        );

    fcs_init_and_encode_state(&delta, local_variant, &(init_state), &enc_state);

    fc_solve_meta_compact_allocator_init(&meta_alloc);
    fc_solve_compact_allocator_init(&allocator, &meta_alloc);

    instance_solver_thread_calc_derived_states(local_variant, &init_state, NULL,
        &derived_list, &derived_list_recycle_bin, &allocator,
        perform_horne_prune);

    iter = derived_list;

    while (iter)
    {
        states_count++;
        iter = iter->next;
    }

    *(num_out_derived_states) = states_count;

    fcs_derived_state_debug_t *const debug_ret =
        SMALLOC(debug_ret, states_count);
    *(out_derived_states) = debug_ret;

    fc_solve_init_locs(&locs);

    iter = derived_list;
    size_t idx = 0;
    while (iter)
    {
        debug_ret[idx] = (typeof(debug_ret[idx])){
            .state_string = SMALLOC(debug_ret[idx].state_string, 1000),
            .move = iter->move,
            .core_irreversible_moves_count =
                iter->core_irreversible_moves_count,
            .num_non_reversible_moves_including_prune =
                iter->num_non_reversible_moves_including_prune,
            .which_irreversible_moves_bitmask =
                iter->which_irreversible_moves_bitmask};
        FCS__RENDER_STATE(debug_ret[idx].state_string, &(iter->state.s), &locs);
        /* TODO : Put something meaningful there by passing it to the function.
         */
        idx++;
        iter = iter->next;
    }

    assert(idx == states_count);

    fc_solve_compact_allocator_finish(&allocator);
    fc_solve_meta_compact_allocator_finish(&meta_alloc);

    fc_solve_delta_stater_release(&delta);

    return 0;
}

/*
 * The char * returned is malloc()ed and should be free()ed.
 */
DLLEXPORT int fc_solve_user_INTERNAL_perform_horne_prune(
    fcs_dbm_variant_type_t local_variant, const char *init_state_str_proto,
    char **ret_state_s)
{
    fcs_state_keyval_pair_t init_state;
    fcs_state_locs_struct_t locs;
    int prune_ret;

    DECLARE_IND_BUF_T(indirect_stacks_buffer)

    fc_solve_init_locs(&locs);

    fc_solve_initial_user_state_to_c(init_state_str_proto, &init_state,
        FREECELLS_NUM, STACKS_NUM, DECKS_NUM, indirect_stacks_buffer);

    prune_ret = horne_prune__simple(local_variant, &init_state);
    *ret_state_s = SMALLOC(*ret_state_s, 1000);
    FCS__RENDER_STATE(*ret_state_s, &(init_state.s), &locs);

    return prune_ret;
}
Beispiel #3
0
static inline void instance__inspect_new_state(
    fcs_dbm_solver_instance_t *const instance, fcs_cache_key_t *const state)
{
    instance->count_num_processed++;

    if (fcs_pdfs_cache_does_key_exist(&(instance->cache), &(state->s)))
    {
        instance->stack_depth--;
        return;
    }
    const fcs_dbm_variant_type_t local_variant = instance->local_variant;
    const int depth = (instance->stack_depth);
    const int max_depth = instance->max_stack_depth;
    if (depth == max_depth)
    {
        instance->stack =
            SREALLOC(instance->stack, ++(instance->max_stack_depth));
        pseduo_dfs_stack_item_t *const stack_item = instance->stack + max_depth;
        stack_item->next_states = NULL;
        stack_item->max_count_next_states = 0;
    }
    pseduo_dfs_stack_item_t *const stack_item = instance->stack + depth;
    stack_item->curr_state = state;

    fcs_derived_state_t *derived_list = NULL, *derived_iter = NULL;

    if (instance_solver_thread_calc_derived_states(instance->local_variant,
            state, NULL, &derived_list, &(instance->derived_list_recycle_bin),
            &(instance->derived_list_allocator), TRUE))
    {
        instance->should_terminate = SOLUTION_FOUND_TERMINATE;
        instance->solution_was_found = TRUE;
        return;
    }

    stack_item->count_next_states = 0;
    stack_item->next_state_idx = 0;
    fcs_kv_state_t kv;
    /* Now recycle the derived_list */
    while (derived_list)
    {
        kv.key = &(derived_list->state.s);
        kv.val = &(derived_list->state.info);
        fc_solve_canonize_state(kv.key, FREECELLS_NUM, STACKS_NUM);

        if (!lookup_state(
                &(instance->store), &(instance->cache), &(derived_list->state)))
        {
            int i = (stack_item->count_next_states)++;
            if (i >= stack_item->max_count_next_states)
            {
                stack_item->next_states = SREALLOC(stack_item->next_states,
                    ++(stack_item->max_count_next_states));
            }
            stack_item->next_states[i] = derived_list->state;
            insert_state(&(instance->store), &(stack_item->next_states[i]));
        }
#define derived_list_next derived_iter
        derived_list_next = derived_list->next;
        derived_list->next = instance->derived_list_recycle_bin;
        instance->derived_list_recycle_bin = derived_list;
        derived_list = derived_list_next;
#undef derived_list_next
    }

    return;
}
Beispiel #4
0
static void *instance_run_solver_thread(void *const void_arg)
{
    fcs_dbm_queue_item_t physical_item;
    fcs_dbm_record_t *token = NULL;
    fcs_dbm_queue_item_t *item, *prev_item;
    fcs_derived_state_t *derived_list, *derived_list_recycle_bin, *derived_iter;
    fcs_compact_allocator_t derived_list_allocator;
    fcs_state_keyval_pair_t state;
    char *base64_encoding_buffer = NULL;
#if 0
    size_t base64_encoding_buffer_max_len = 0;
#endif

#ifdef DEBUG_OUT
    fcs_state_locs_struct_t locs;
    fc_solve_init_locs(&locs);
#endif
    DECLARE_IND_BUF_T(indirect_stacks_buffer)

    const_AUTO(thread, ((thread_arg_t *)void_arg)->thread);
    const_SLOT(instance, thread);
    const_AUTO(delta_stater, &(thread->delta_stater));
    const_AUTO(local_variant, instance->common.variant);

    prev_item = item = NULL;
    int queue_num_extracted_and_processed = 0;
    fc_solve_compact_allocator_init(
        &(derived_list_allocator), &(thread->thread_meta_alloc));
    derived_list_recycle_bin = NULL;
    derived_list = NULL;
    FILE *const out_fh = instance->common.out_fh;
    TRACE("%s\n", "instance_run_solver_thread start");
    const_AUTO(coll, &(instance->coll));
#if 0
    fcs_bool_t was_start_key_reachable = instance->was_start_key_reachable;
#endif
    while (1)
    {
        /* First of all extract an item. */
        fcs_lock_lock(&instance->global_lock);

        if (prev_item)
        {
            instance->common.queue_num_extracted_and_processed--;
        }

        if (instance->common.should_terminate == DONT_TERMINATE)
        {
            if (fcs_depth_multi_queue__extract(&(coll->depth_queue),
                    &(thread->state_depth),
                    (fcs_offloading_queue_item_t *)(&token)))
            {
                physical_item.key = token->key;
                item = &physical_item;
                instance_increment(instance);
            }
            else
            {
                item = NULL;
            }

            queue_num_extracted_and_processed =
                instance->common.queue_num_extracted_and_processed;
        }
        fcs_lock_unlock(&instance->global_lock);

        if ((instance->common.should_terminate != DONT_TERMINATE) ||
            (!queue_num_extracted_and_processed))
        {
            break;
        }

        if (!item)
        {
            /* Sleep until more items become available in the
             * queue. */
            usleep(5000);
        }
        else
        {
            /* Handle item. */
            fc_solve_delta_stater_decode_into_state(
                delta_stater, item->key.s, &state, indirect_stacks_buffer);

            /* A section for debugging. */
            FCS__OUTPUT_STATE(out_fh, "", &(state.s), &locs);
#if 0
        {
            FccEntryPointNode key;
            key.kv.key.key = item->key;
            fcs_lock_lock(&instance->fcc_entry_points_lock);
            FccEntryPointNode * val_proto = RB_FIND(
                FccEntryPointList,
                &(instance->fcc_entry_points),
                &(key)
            );

            fcs_bool_t to_prune = FALSE;
            fcs_bool_t to_output = FALSE;
            if (val_proto)
            {
                val_proto->kv.val.is_reachable = TRUE;
                const int moves_count = instance->start_key_moves_count
                    + item->moves_seq.count;

                if (was_start_key_reachable)
                {
                    if (val_proto->kv.val.depth <= moves_count)
                    {
                        /* We can prune based on here. */
                        to_prune = TRUE;
                    }
                    else
                    {
                        /* We can set it to the more pessimstic move count
                         * for future trimming. */
                        to_output = !(val_proto->kv.val.was_consumed);
                        val_proto->kv.val.depth = moves_count;
                        val_proto->kv.val.was_consumed = TRUE;
                    }
                }
                else
                {
                    if (! val_proto->kv.val.was_consumed)
                    {
                        to_output = TRUE;
                        if (val_proto->kv.val.depth >= moves_count)
                        {
                            val_proto->kv.val.depth = moves_count;
                            val_proto->kv.val.was_consumed = TRUE;
                        }
                    }
                }
            }
            fcs_lock_unlock(&instance->fcc_entry_points_lock);

            if (to_output)
            {
                const size_t needed_len = ( (sizeof(key.kv.key.key)+2) << 2 ) / 3 + 20;
                if (base64_encoding_buffer_max_len < needed_len)
                {
                    base64_encoding_buffer = SREALLOC(base64_encoding_buffer, needed_len);
                    base64_encoding_buffer_max_len = needed_len;
                }

                size_t unused_output_len;

                base64_encode(
                    (unsigned char *)&(key.kv.key.key),
                    sizeof(key.kv.key.key),
                    base64_encoding_buffer,
                    &unused_output_len
                );

                fcs_lock_lock(&instance->output_lock);
                fprintf(
                    instance->consumed_states_fh,
                    "%s\n", base64_encoding_buffer
                );
                fflush(instance->consumed_states_fh);
                fcs_lock_unlock(&instance->output_lock);
            }

            if (to_prune)
            {
                continue;
            }
        }
#endif

            if (instance_solver_thread_calc_derived_states(local_variant,
                    &state, token, &derived_list, &derived_list_recycle_bin,
                    &derived_list_allocator, TRUE))
            {
                fcs_lock_lock(&instance->global_lock);
                fcs_dbm__found_solution(&(instance->common), token, item);
                fcs_lock_unlock(&instance->global_lock);
                break;
            }

            /* Encode all the states. */
            for (derived_iter = derived_list; derived_iter;
                 derived_iter = derived_iter->next)
            {
                fcs_init_and_encode_state(delta_stater, local_variant,
                    &(derived_iter->state), &(derived_iter->key));
            }

            instance_check_multiple_keys(thread, instance, &(coll->cache_store),
                &(coll->queue_meta_alloc), &derived_list, 1
#ifdef FCS_DBM_CACHE_ONLY
                ,
                item->moves_to_key
#endif
                );

            /* Now recycle the derived_list */
            while (derived_list)
            {
#define derived_list_next derived_iter
                derived_list_next = derived_list->next;
                derived_list->next = derived_list_recycle_bin;
                derived_list_recycle_bin = derived_list;
                derived_list = derived_list_next;
#undef derived_list_next
            }
            /* End handle item. */
        }
        /* End of main thread loop */
        prev_item = item;
    }

    free(base64_encoding_buffer);

    fc_solve_compact_allocator_finish(&(derived_list_allocator));

    TRACE("%s\n", "instance_run_solver_thread end");

    return NULL;
}