diff --git a/benchmarks/benchmarks/XSbench/GridInit.c b/benchmarks/benchmarks/XSbench/GridInit.c deleted file mode 100644 index 08a0f27..0000000 --- a/benchmarks/benchmarks/XSbench/GridInit.c +++ /dev/null @@ -1,230 +0,0 @@ -#include "XSbench_header.h" - -SimulationData grid_init_do_not_profile( Inputs in, int mype ) -{ - // Structure to hold all allocated simuluation data arrays - SimulationData SD; - - // Keep track of how much data we're allocating - size_t nbytes = 0; - - // Set the initial seed value - uint64_t seed = 42; - - // loop variable - long e = 0; - - //////////////////////////////////////////////////////////////////// - // Initialize Nuclide Grids - //////////////////////////////////////////////////////////////////// - - if(mype == 0) printf("Intializing nuclide grids...\n"); - - // First, we need to initialize our nuclide grid. This comes in the form - // of a flattened 2D array that hold all the information we need to define - // the cross sections for all isotopes in the simulation. - // The grid is composed of "NuclideGridPoint" structures, which hold the - // energy level of the grid point and all associated XS data at that level. - // An array of structures (AOS) is used instead of - // a structure of arrays, as the grid points themselves are accessed in - // a random order, but all cross section interaction channels and the - // energy level are read whenever the gridpoint is accessed, meaning the - // AOS is more cache efficient. - - // Initialize Nuclide Grid - SD.length_nuclide_grid = in.n_isotopes * in.n_gridpoints; - SD.nuclide_grid = (NuclideGridPoint *) malloc( SD.length_nuclide_grid * sizeof(NuclideGridPoint)); - assert(SD.nuclide_grid != NULL); - nbytes += SD.length_nuclide_grid * sizeof(NuclideGridPoint); - for( int i = 0; i < SD.length_nuclide_grid; i++ ) - { - SD.nuclide_grid[i].energy = LCG_random_double(&seed); - SD.nuclide_grid[i].total_xs = LCG_random_double(&seed); - SD.nuclide_grid[i].elastic_xs = LCG_random_double(&seed); - SD.nuclide_grid[i].absorbtion_xs = LCG_random_double(&seed); - SD.nuclide_grid[i].fission_xs = LCG_random_double(&seed); - SD.nuclide_grid[i].nu_fission_xs = LCG_random_double(&seed); - } - - // Sort so that each nuclide has data stored in ascending energy order. - for( int i = 0; i < in.n_isotopes; i++ ) - qsort( &SD.nuclide_grid[i*in.n_gridpoints], in.n_gridpoints, sizeof(NuclideGridPoint), NGP_compare); - - // error debug check - /* - for( int i = 0; i < in.n_isotopes; i++ ) - { - printf("NUCLIDE %d ==============================\n", i); - for( int j = 0; j < in.n_gridpoints; j++ ) - printf("E%d = %lf\n", j, SD.nuclide_grid[i * in.n_gridpoints + j].energy); - } - */ - - - //////////////////////////////////////////////////////////////////// - // Initialize Acceleration Structure - //////////////////////////////////////////////////////////////////// - - if( in.grid_type == NUCLIDE ) - { - SD.length_unionized_energy_array = 0; - SD.length_index_grid = 0; - } - - if( in.grid_type == UNIONIZED ) - { - if(mype == 0) printf("Intializing unionized grid...\n"); - - // Allocate space to hold the union of all nuclide energy data - SD.length_unionized_energy_array = in.n_isotopes * in.n_gridpoints; - SD.unionized_energy_array = (double *) malloc( SD.length_unionized_energy_array * sizeof(double)); - assert(SD.unionized_energy_array != NULL ); - nbytes += SD.length_unionized_energy_array * sizeof(double); - - // Copy energy data over from the nuclide energy grid - for( int i = 0; i < SD.length_unionized_energy_array; i++ ) - SD.unionized_energy_array[i] = SD.nuclide_grid[i].energy; - - // Sort unionized energy array - qsort( SD.unionized_energy_array, SD.length_unionized_energy_array, sizeof(double), double_compare); - - // Allocate space to hold the acceleration grid indices - SD.length_index_grid = SD.length_unionized_energy_array * in.n_isotopes; - SD.index_grid = (int *) malloc( SD.length_index_grid * sizeof(int)); - assert(SD.index_grid != NULL); - nbytes += SD.length_index_grid * sizeof(int); - - // Generates the double indexing grid - int * idx_low = (int *) calloc( in.n_isotopes, sizeof(int)); - assert(idx_low != NULL ); - double * energy_high = (double *) malloc( in.n_isotopes * sizeof(double)); - assert(energy_high != NULL ); - - for( int i = 0; i < in.n_isotopes; i++ ) - energy_high[i] = SD.nuclide_grid[i * in.n_gridpoints + 1].energy; - - for( long e = 0; e < SD.length_unionized_energy_array; e++ ) - { - double unionized_energy = SD.unionized_energy_array[e]; - for( long i = 0; i < in.n_isotopes; i++ ) - { - if( unionized_energy < energy_high[i] ) - SD.index_grid[e * in.n_isotopes + i] = idx_low[i]; - else if( idx_low[i] == in.n_gridpoints - 2 ) - SD.index_grid[e * in.n_isotopes + i] = idx_low[i]; - else - { - idx_low[i]++; - SD.index_grid[e * in.n_isotopes + i] = idx_low[i]; - energy_high[i] = SD.nuclide_grid[i * in.n_gridpoints + idx_low[i] + 1].energy; - } - } - } - - free(idx_low); - free(energy_high); - } - - if( in.grid_type == HASH ) - { - if(mype == 0) printf("Intializing hash grid...\n"); - SD.length_unionized_energy_array = 0; - SD.length_index_grid = in.hash_bins * in.n_isotopes; - SD.index_grid = (int *) malloc( SD.length_index_grid * sizeof(int)); - assert(SD.index_grid != NULL); - nbytes += SD.length_index_grid * sizeof(int); - - double du = 1.0 / in.hash_bins; - - // For each energy level in the hash table - #pragma omp parallel for - for( e = 0; e < in.hash_bins; e++ ) - { - double energy = e * du; - - // We need to determine the bounding energy levels for all isotopes - for( long i = 0; i < in.n_isotopes; i++ ) - { - SD.index_grid[e * in.n_isotopes + i] = grid_search_nuclide( in.n_gridpoints, energy, SD.nuclide_grid + i * in.n_gridpoints, 0, in.n_gridpoints-1); - } - } - } - - //////////////////////////////////////////////////////////////////// - // Initialize Materials and Concentrations - //////////////////////////////////////////////////////////////////// - if(mype == 0) printf("Intializing material data...\n"); - - // Set the number of nuclides in each material - SD.num_nucs = load_num_nucs(in.n_isotopes); - SD.length_num_nucs = 12; // There are always 12 materials in XSBench - - // Intialize the flattened 2D grid of material data. The grid holds - // a list of nuclide indices for each of the 12 material types. The - // grid is allocated as a full square grid, even though not all - // materials have the same number of nuclides. - SD.mats = load_mats(SD.num_nucs, in.n_isotopes, &SD.max_num_nucs); - SD.length_mats = SD.length_num_nucs * SD.max_num_nucs; - - // Intialize the flattened 2D grid of nuclide concentration data. The grid holds - // a list of nuclide concentrations for each of the 12 material types. The - // grid is allocated as a full square grid, even though not all - // materials have the same number of nuclides. - SD.concs = load_concs(SD.num_nucs, SD.max_num_nucs); - SD.length_concs = SD.length_mats; - - // Allocate and initialize replicas -#ifdef AML - // num_nucs - aml_replicaset_hwloc_create(&(SD.num_nucs_replica), - SD.length_num_nucs * sizeof(*(SD.num_nucs)), - HWLOC_OBJ_CORE, - HWLOC_DISTANCES_KIND_FROM_OS | - HWLOC_DISTANCES_KIND_MEANS_LATENCY); - nbytes += (SD.num_nucs_replica)->n * (SD.num_nucs_replica)->size; - aml_replicaset_init(SD.num_nucs_replica, SD.num_nucs); - - // concs - aml_replicaset_hwloc_create(&(SD.concs_replica), - SD.length_concs * sizeof(*(SD.concs)), - HWLOC_OBJ_CORE, - HWLOC_DISTANCES_KIND_FROM_OS | - HWLOC_DISTANCES_KIND_MEANS_LATENCY); - nbytes += (SD.concs_replica)->n * (SD.concs_replica)->size; - aml_replicaset_init(SD.concs_replica, SD.concs); - - // unionized_energy_array - if( in.grid_type == UNIONIZED ){ - aml_replicaset_hwloc_create(&(SD.unionized_energy_array_replica), - SD.length_unionized_energy_array * sizeof(*(SD.unionized_energy_array)), - HWLOC_OBJ_CORE, - HWLOC_DISTANCES_KIND_FROM_OS | - HWLOC_DISTANCES_KIND_MEANS_LATENCY); - nbytes += (SD.unionized_energy_array_replica)->n * (SD.unionized_energy_array_replica)->size; - aml_replicaset_init(SD.unionized_energy_array_replica, SD.unionized_energy_array); - } - - // index grid - if( in.grid_type == UNIONIZED || in.grid_type == HASH ){ - aml_replicaset_hwloc_create(&(SD.index_grid_replica), - SD.length_index_grid * sizeof(*(SD.index_grid)), - HWLOC_OBJ_CORE, - HWLOC_DISTANCES_KIND_FROM_OS | - HWLOC_DISTANCES_KIND_MEANS_LATENCY); - nbytes += (SD.index_grid_replica)->n * (SD.index_grid_replica)->size; - aml_replicaset_init(SD.index_grid_replica, SD.index_grid); - } - - // nuclide grid - aml_replicaset_hwloc_create(&(SD.nuclide_grid_replica), - SD.length_nuclide_grid * sizeof(*(SD.nuclide_grid)), - HWLOC_OBJ_CORE, - HWLOC_DISTANCES_KIND_FROM_OS | - HWLOC_DISTANCES_KIND_MEANS_LATENCY); - nbytes += (SD.nuclide_grid_replica)->n * (SD.nuclide_grid_replica)->size; - aml_replicaset_init(SD.nuclide_grid_replica, SD.nuclide_grid); -#endif - - if(mype == 0) printf("Intialization complete. Allocated %.0lf MB of data.\n", nbytes/1024.0/1024.0 ); - return SD; -} \ No newline at end of file diff --git a/benchmarks/benchmarks/XSbench/Main.c b/benchmarks/benchmarks/XSbench/Main.c deleted file mode 100644 index 6498bec..0000000 --- a/benchmarks/benchmarks/XSbench/Main.c +++ /dev/null @@ -1,123 +0,0 @@ -#include "XSbench_header.h" - -#ifdef MPI -#include -#endif - -int main( int argc, char* argv[] ) -{ - // ===================================================================== - // Initialization & Command Line Read-In - // ===================================================================== - int version = 20; - int mype = 0; - double omp_start, omp_end; - int nprocs = 1; - unsigned long long verification; - - #ifdef MPI - MPI_Init(&argc, &argv); - MPI_Comm_size(MPI_COMM_WORLD, &nprocs); - MPI_Comm_rank(MPI_COMM_WORLD, &mype); - #endif - - #ifdef AML - aml_init(&argc, &argv); - #endif - - // Process CLI Fields -- store in "Inputs" structure - Inputs in = read_CLI( argc, argv ); - - // Set number of OpenMP Threads - #ifdef OPENMP - omp_set_num_threads(in.nthreads); - #endif - - // Print-out of Input Summary - if( mype == 0 ) - print_inputs( in, nprocs, version ); - - // ===================================================================== - // Prepare Nuclide Energy Grids, Unionized Energy Grid, & Material Data - // This is not reflective of a real Monte Carlo simulation workload, - // therefore, do not profile this region! - // ===================================================================== - - SimulationData SD; - - // If read from file mode is selected, skip initialization and load - // all simulation data structures from file instead - if( in.binary_mode == READ ) - SD = binary_read(in); - else - SD = grid_init_do_not_profile( in, mype ); - - // If writing from file mode is selected, write all simulation data - // structures to file - if( in.binary_mode == WRITE && mype == 0 ) - binary_write(in, SD); - - - // ===================================================================== - // Cross Section (XS) Parallel Lookup Simulation - // This is the section that should be profiled, as it reflects a - // realistic continuous energy Monte Carlo macroscopic cross section - // lookup kernel. - // ===================================================================== - - if( mype == 0 ) - { - printf("\n"); - border_print(); - center_print("SIMULATION", 79); - border_print(); - } - - // Start Simulation Timer - omp_start = get_time(); - - // Run simulation - if( in.simulation_method == EVENT_BASED ) - { - if( in.kernel_id == 0 ) - verification = run_event_based_simulation(in, SD, mype); - else if( in.kernel_id == 1 ) - verification = run_event_based_simulation_optimization_1(in, SD, mype); - else - { - printf("Error: No kernel ID %d found!\n", in.kernel_id); - exit(1); - } - } - else - verification = run_history_based_simulation(in, SD, mype); - - if( mype == 0) - { - printf("\n" ); - printf("Simulation complete.\n" ); - } - - // End Simulation Timer - omp_end = get_time(); - - // ===================================================================== - // Output Results & Finalize - // ===================================================================== - - // Final Hash Step - verification = verification % 999983; - - // Print / Save Results and Exit - int is_invalid_result = print_results( in, mype, omp_end-omp_start, nprocs, verification ); - - #ifdef MPI - MPI_Finalize(); - #endif - - #ifdef AML - aml_finalize(); - #endif - - return is_invalid_result; -} \ No newline at end of file diff --git a/benchmarks/benchmarks/XSbench/Makefile b/benchmarks/benchmarks/XSbench/Makefile deleted file mode 100644 index 4fcfab8..0000000 --- a/benchmarks/benchmarks/XSbench/Makefile +++ /dev/null @@ -1,86 +0,0 @@ -#=============================================================================== -# User Options -#=============================================================================== - -# Compiler can be set below, or via environment variable -CC = cc -OPTIMIZE = yes -OPENMP = no -DEBUG = yes -PROFILE = no -MPI = no -AML = no - -#=============================================================================== -# Program name & source code list -#=============================================================================== - -program = XSBench - -source = \ -Main.c \ -io.c \ -Simulations.c \ -GridInit.c \ -XSutils.c \ -Materials.c - -obj = $(source:.c=.o) - -#=============================================================================== -# Sets Flags -#=============================================================================== - -# Standard Flags - -# Linker Flags -LDFLAGS = -lm - -# LLVM Compiler -# ifneq (,$(findstring clang,$(CC))) -# CFLAGS += -flto -# ifeq ($(OPENMP),yes) -# CFLAGS += -fopenmp -DOPENMP -# endif -# endif - -# # Intel Compiler -# ifneq (,$(findstring intel,$(CC))) -# CFLAGS += -ipo -# ifeq ($(OPENMP),yes) -# CFLAGS += -fopenmp -DOPENMP -# endif -# endif - -# # Debug Flags -# ifeq ($(DEBUG),yes) -# CFLAGS += -g -# LDFLAGS += -g -# endif - -# Profiling Flags - -# Optimization Flags - -# AML - -CFLAGS += -g -Wall -mabi=purecap-benchmark -lpthread - -#=============================================================================== -# Targets to Build -#=============================================================================== - -$(program): $(obj) XSbench_header.h Makefile - $(CC) $(CFLAGS) $(obj) -o $@ $(LDFLAGS) - -%.o: %.c XSbench_header.h Makefile - $(CC) $(CFLAGS) -c $< -o $@ - -clean: - rm -rf $(program) $(obj) - -edit: - vim -p $(source) XSbench_header.h - -run: - ./$(program) diff --git a/benchmarks/benchmarks/XSbench/Materials.c b/benchmarks/benchmarks/XSbench/Materials.c deleted file mode 100644 index 5606aeb..0000000 --- a/benchmarks/benchmarks/XSbench/Materials.c +++ /dev/null @@ -1,117 +0,0 @@ - -// Material data is hard coded into the functions in this file. -// Note that there are 12 materials present in H-M (large or small) - -#include "XSbench_header.h" - -// num_nucs represents the number of nuclides that each material contains -int * load_num_nucs(long n_isotopes) -{ - int * num_nucs = (int*)malloc(12*sizeof(int)); - - // Material 0 is a special case (fuel). The H-M small reactor uses - // 34 nuclides, while H-M larges uses 300. - if( n_isotopes == 68 ) - num_nucs[0] = 34; // HM Small is 34, H-M Large is 321 - else - num_nucs[0] = 321; // HM Small is 34, H-M Large is 321 - - num_nucs[1] = 5; - num_nucs[2] = 4; - num_nucs[3] = 4; - num_nucs[4] = 27; - num_nucs[5] = 21; - num_nucs[6] = 21; - num_nucs[7] = 21; - num_nucs[8] = 21; - num_nucs[9] = 21; - num_nucs[10] = 9; - num_nucs[11] = 9; - - return num_nucs; -} - -// Assigns an array of nuclide ID's to each material -int * load_mats( int * num_nucs, long n_isotopes, int * max_num_nucs ) -{ - *max_num_nucs = 0; - int num_mats = 12; - for( int m = 0; m < num_mats; m++ ) - { - if( num_nucs[m] > *max_num_nucs ) - *max_num_nucs = num_nucs[m]; - } - int * mats = (int *) malloc( num_mats * (*max_num_nucs) * sizeof(int) ); - - // Small H-M has 34 fuel nuclides - int mats0_Sml[] = { 58, 59, 60, 61, 40, 42, 43, 44, 45, 46, 1, 2, 3, 7, - 8, 9, 10, 29, 57, 47, 48, 0, 62, 15, 33, 34, 52, 53, - 54, 55, 56, 18, 23, 41 }; //fuel - // Large H-M has 300 fuel nuclides - int mats0_Lrg[321] = { 58, 59, 60, 61, 40, 42, 43, 44, 45, 46, 1, 2, 3, 7, - 8, 9, 10, 29, 57, 47, 48, 0, 62, 15, 33, 34, 52, 53, - 54, 55, 56, 18, 23, 41 }; //fuel - for( int i = 0; i < 321-34; i++ ) - mats0_Lrg[34+i] = 68 + i; // H-M large adds nuclides to fuel only - - // These are the non-fuel materials - int mats1[] = { 63, 64, 65, 66, 67 }; // cladding - int mats2[] = { 24, 41, 4, 5 }; // cold borated water - int mats3[] = { 24, 41, 4, 5 }; // hot borated water - int mats4[] = { 19, 20, 21, 22, 35, 36, 37, 38, 39, 25, 27, 28, 29, - 30, 31, 32, 26, 49, 50, 51, 11, 12, 13, 14, 6, 16, - 17 }; // RPV - int mats5[] = { 24, 41, 4, 5, 19, 20, 21, 22, 35, 36, 37, 38, 39, 25, - 49, 50, 51, 11, 12, 13, 14 }; // lower radial reflector - int mats6[] = { 24, 41, 4, 5, 19, 20, 21, 22, 35, 36, 37, 38, 39, 25, - 49, 50, 51, 11, 12, 13, 14 }; // top reflector / plate - int mats7[] = { 24, 41, 4, 5, 19, 20, 21, 22, 35, 36, 37, 38, 39, 25, - 49, 50, 51, 11, 12, 13, 14 }; // bottom plate - int mats8[] = { 24, 41, 4, 5, 19, 20, 21, 22, 35, 36, 37, 38, 39, 25, - 49, 50, 51, 11, 12, 13, 14 }; // bottom nozzle - int mats9[] = { 24, 41, 4, 5, 19, 20, 21, 22, 35, 36, 37, 38, 39, 25, - 49, 50, 51, 11, 12, 13, 14 }; // top nozzle - int mats10[] = { 24, 41, 4, 5, 63, 64, 65, 66, 67 }; // top of FA's - int mats11[] = { 24, 41, 4, 5, 63, 64, 65, 66, 67 }; // bottom FA's - - // H-M large v small dependency - if( n_isotopes == 68 ) - memcpy( mats, mats0_Sml, num_nucs[0] * sizeof(int) ); - else - memcpy( mats, mats0_Lrg, num_nucs[0] * sizeof(int) ); - - // Copy other materials - memcpy( mats + *max_num_nucs * 1, mats1, num_nucs[1] * sizeof(int) ); - memcpy( mats + *max_num_nucs * 2, mats2, num_nucs[2] * sizeof(int) ); - memcpy( mats + *max_num_nucs * 3, mats3, num_nucs[3] * sizeof(int) ); - memcpy( mats + *max_num_nucs * 4, mats4, num_nucs[4] * sizeof(int) ); - memcpy( mats + *max_num_nucs * 5, mats5, num_nucs[5] * sizeof(int) ); - memcpy( mats + *max_num_nucs * 6, mats6, num_nucs[6] * sizeof(int) ); - memcpy( mats + *max_num_nucs * 7, mats7, num_nucs[7] * sizeof(int) ); - memcpy( mats + *max_num_nucs * 8, mats8, num_nucs[8] * sizeof(int) ); - memcpy( mats + *max_num_nucs * 9, mats9, num_nucs[9] * sizeof(int) ); - memcpy( mats + *max_num_nucs * 10, mats10, num_nucs[10] * sizeof(int) ); - memcpy( mats + *max_num_nucs * 11, mats11, num_nucs[11] * sizeof(int) ); - - return mats; -} - -// Randomizes the concentrations of all nuclides in a variety of materials -double * load_concs( int * num_nucs, int max_num_nucs ) -{ - uint64_t seed = STARTING_SEED * STARTING_SEED; - double * concs = (double *) malloc( 12 * max_num_nucs * sizeof( double ) ); - - for( int i = 0; i < 12; i++ ) - for( int j = 0; j < num_nucs[i]; j++ ) - concs[i * max_num_nucs + j] = LCG_random_double(&seed); - - // test - /* - for( int i = 0; i < 12; i++ ) - for( int j = 0; j < num_nucs[i]; j++ ) - printf("concs[%d][%d] = %lf\n", i, j, concs[i][j] ); - */ - - return concs; -} diff --git a/benchmarks/benchmarks/XSbench/Simulations.c b/benchmarks/benchmarks/XSbench/Simulations.c deleted file mode 100644 index 0676e48..0000000 --- a/benchmarks/benchmarks/XSbench/Simulations.c +++ /dev/null @@ -1,871 +0,0 @@ -#include "XSbench_header.h" - -//////////////////////////////////////////////////////////////////////////////////// -// BASELINE FUNCTIONS -//////////////////////////////////////////////////////////////////////////////////// -// All "baseline" code is at the top of this file. The baseline code is a simple -// implementation of the algorithm, with only minor CPU optimizations in place. -// Following these functions are a number of optimized variants, -// which each deploy a different combination of optimizations strategies. By -// default, XSBench will only run the baseline implementation. Optimized variants -// must be specifically selected using the "-k " command -// line argument. -//////////////////////////////////////////////////////////////////////////////////// - -unsigned long long run_event_based_simulation(Inputs in, SimulationData SD, int mype) -{ - if( mype == 0) - printf("Beginning event based simulation...\n"); - - //////////////////////////////////////////////////////////////////////////////// - // SUMMARY: Simulation Data Structure Manifest for "SD" Object - // Here we list all heap arrays (and lengths) in SD that would need to be - // offloaded manually if using an accelerator with a seperate memory space - //////////////////////////////////////////////////////////////////////////////// - // int * num_nucs; // Length = length_num_nucs; - // double * concs; // Length = length_concs - // int * mats; // Length = length_mats - // double * unionized_energy_array; // Length = length_unionized_energy_array - // int * index_grid; // Length = length_index_grid - // NuclideGridPoint * nuclide_grid; // Length = length_nuclide_grid - // - // Note: "unionized_energy_array" and "index_grid" can be of zero length - // depending on lookup method. - // - // Note: "Lengths" are given as the number of objects in the array, not the - // number of bytes. - //////////////////////////////////////////////////////////////////////////////// - - - //////////////////////////////////////////////////////////////////////////////// - // Begin Actual Simulation Loop - //////////////////////////////////////////////////////////////////////////////// - unsigned long long verification = 0; - int i = 0; - #pragma omp parallel for schedule(dynamic,100) reduction(+:verification) - for( i = 0; i < in.lookups; i++ ) - { - #ifdef AML - int * num_nucs = aml_replicaset_hwloc_local_replica(SD.num_nucs_replica); - double * concs = aml_replicaset_hwloc_local_replica(SD.concs_replica); - double * unionized_energy_array = aml_replicaset_hwloc_local_replica(SD.unionized_energy_array_replica); - int * index_grid = aml_replicaset_hwloc_local_replica(SD.index_grid_replica); - NuclideGridPoint * nuclide_grid = aml_replicaset_hwloc_local_replica(SD.nuclide_grid_replica); - #else - int * num_nucs = SD.num_nucs; - double * concs = SD.concs; - double * unionized_energy_array = SD.unionized_energy_array; - int * index_grid = SD.index_grid; - NuclideGridPoint * nuclide_grid = SD.nuclide_grid; - #endif - - // Set the initial seed value - uint64_t seed = STARTING_SEED; - - // Forward seed to lookup index (we need 2 samples per lookup) - seed = fast_forward_LCG(seed, 2*i); - - // Randomly pick an energy and material for the particle - double p_energy = LCG_random_double(&seed); - int mat = pick_mat(&seed); - - double macro_xs_vector[5] = {0}; - - // Perform macroscopic Cross Section Lookup - calculate_macro_xs( - p_energy, // Sampled neutron energy (in lethargy) - mat, // Sampled material type index neutron is in - in.n_isotopes, // Total number of isotopes in simulation - in.n_gridpoints, // Number of gridpoints per isotope in simulation - num_nucs, // 1-D array with number of nuclides per material - concs, // Flattened 2-D array with concentration of each nuclide in each material - unionized_energy_array, // 1-D Unionized energy array - index_grid, // Flattened 2-D grid holding indices into nuclide grid for each unionized energy level - nuclide_grid, // Flattened 2-D grid holding energy levels and XS_data for all nuclides in simulation - SD.mats, // Flattened 2-D array with nuclide indices defining composition of each type of material - macro_xs_vector, // 1-D array with result of the macroscopic cross section (5 different reaction channels) - in.grid_type, // Lookup type (nuclide, hash, or unionized) - in.hash_bins, // Number of hash bins used (if using hash lookup type) - SD.max_num_nucs // Maximum number of nuclides present in any material - ); - - // For verification, and to prevent the compiler from optimizing - // all work out, we interrogate the returned macro_xs_vector array - // to find its maximum value index, then increment the verification - // value by that index. In this implementation, we prevent thread - // contention by using an OMP reduction on the verification value. - // For accelerators, a different approach might be required - // (e.g., atomics, reduction of thread-specific values in large - // array via CUDA thrust, etc). - double max = -1.0; - int max_idx = 0; - for(int j = 0; j < 5; j++ ) - { - if( macro_xs_vector[j] > max ) - { - max = macro_xs_vector[j]; - max_idx = j; - } - } - verification += max_idx+1; - } - - return verification; -} - -unsigned long long run_history_based_simulation(Inputs in, SimulationData SD, int mype) -{ - if( mype == 0) - printf("Beginning history based simulation...\n"); - - - //////////////////////////////////////////////////////////////////////////////// - // SUMMARY: Simulation Data Structure Manifest for "SD" Object - // Here we list all heap arrays (and lengths) in SD that would need to be - // offloaded manually if using an accelerator with a seperate memory space - //////////////////////////////////////////////////////////////////////////////// - // int * num_nucs; // Length = length_num_nucs; - // double * concs; // Length = length_concs - // int * mats; // Length = length_mats - // double * unionized_energy_array; // Length = length_unionized_energy_array - // int * index_grid; // Length = length_index_grid - // NuclideGridPoint * nuclide_grid; // Length = length_nuclide_grid - // - // Note: "unionized_energy_array" and "index_grid" can be of zero length - // depending on lookup method. - // - // Note: "Lengths" are given as the number of objects in the array, not the - // number of bytes. - //////////////////////////////////////////////////////////////////////////////// - - unsigned long long verification = 0; - - // Begin outer lookup loop over particles. This loop is independent. - int p = 0; - #pragma omp parallel for schedule(dynamic, 100) reduction(+:verification) - for( p = 0; p < in.particles; p++ ) - { - #ifdef AML - int * num_nucs = aml_replicaset_hwloc_local_replica(SD.num_nucs_replica); - double * concs = aml_replicaset_hwloc_local_replica(SD.concs_replica); - double * unionized_energy_array = aml_replicaset_hwloc_local_replica(SD.unionized_energy_array_replica); - int * index_grid = aml_replicaset_hwloc_local_replica(SD.index_grid_replica); - NuclideGridPoint * nuclide_grid = aml_replicaset_hwloc_local_replica(SD.nuclide_grid_replica); - #else - int * num_nucs = SD.num_nucs; - double * concs = SD.concs; - double * unionized_energy_array = SD.unionized_energy_array; - int * index_grid = SD.index_grid; - NuclideGridPoint * nuclide_grid = SD.nuclide_grid; - #endif - - // Set the initial seed value - uint64_t seed = STARTING_SEED; - - // Forward seed to lookup index (we need 2 samples per lookup, and - // we may fast forward up to 5 times after each lookup) - seed = fast_forward_LCG(seed, p*in.lookups*2*5); - - // Randomly pick an energy and material for the particle - double p_energy = LCG_random_double(&seed); - int mat = pick_mat(&seed); - - // Inner XS Lookup Loop - // This loop is dependent! - // i.e., Next iteration uses data computed in previous iter. - for( int i = 0; i < in.lookups; i++ ) - { - double macro_xs_vector[5] = {0}; - - // Perform macroscopic Cross Section Lookup - calculate_macro_xs( - p_energy, // Sampled neutron energy (in lethargy) - mat, // Sampled material type neutron is in - in.n_isotopes, // Total number of isotopes in simulation - in.n_gridpoints, // Number of gridpoints per isotope in simulation - num_nucs, // 1-D array with number of nuclides per material - concs, // Flattened 2-D array with concentration of each nuclide in each material - unionized_energy_array, // 1-D Unionized energy array - index_grid, // Flattened 2-D grid holding indices into nuclide grid for each unionized energy level - nuclide_grid, // Flattened 2-D grid holding energy levels and XS_data for all nuclides in simulation - SD.mats, // Flattened 2-D array with nuclide indices for each type of material - macro_xs_vector, // 1-D array with result of the macroscopic cross section (5 different reaction channels) - in.grid_type, // Lookup type (nuclide, hash, or unionized) - in.hash_bins, // Number of hash bins used (if using hash lookups) - SD.max_num_nucs // Maximum number of nuclides present in any material - ); - - - // For verification, and to prevent the compiler from optimizing - // all work out, we interrogate the returned macro_xs_vector array - // to find its maximum value index, then increment the verification - // value by that index. In this implementation, we prevent thread - // contention by using an OMP reduction on it. For other accelerators, - // a different approach might be required (e.g., atomics, reduction - // of thread-specific values in large array via CUDA thrust, etc) - double max = -1.0; - int max_idx = 0; - for(int j = 0; j < 5; j++ ) - { - if( macro_xs_vector[j] > max ) - { - max = macro_xs_vector[j]; - max_idx = j; - } - } - verification += max_idx+1; - - // Randomly pick next energy and material for the particle - // Also incorporates results from macro_xs lookup to - // enforce loop dependency. - // In a real MC app, this dependency is expressed in terms - // of branching physics sampling, whereas here we are just - // artificially enforcing this dependence based on fast - // forwarding the LCG state - uint64_t n_forward = 0; - for( int j = 0; j < 5; j++ ) - if( macro_xs_vector[j] > 1.0 ) - n_forward++; - if( n_forward > 0 ) - seed = fast_forward_LCG(seed, n_forward); - - p_energy = LCG_random_double(&seed); - mat = pick_mat(&seed); - } - - } - return verification; -} - -// Calculates the microscopic cross section for a given nuclide & energy -void calculate_micro_xs( double p_energy, int nuc, long n_isotopes, - long n_gridpoints, - double * restrict egrid, int * restrict index_data, - NuclideGridPoint * restrict nuclide_grids, - long idx, double * restrict xs_vector, int grid_type, int hash_bins ){ - // Variables - double f; - NuclideGridPoint * low, * high; - - // If using only the nuclide grid, we must perform a binary search - // to find the energy location in this particular nuclide's grid. - if( grid_type == NUCLIDE ) - { - // Perform binary search on the Nuclide Grid to find the index - idx = grid_search_nuclide( n_gridpoints, p_energy, &nuclide_grids[nuc*n_gridpoints], 0, n_gridpoints-1); - - // pull ptr from nuclide grid and check to ensure that - // we're not reading off the end of the nuclide's grid - if( idx == n_gridpoints - 1 ) - low = &nuclide_grids[nuc*n_gridpoints + idx - 1]; - else - low = &nuclide_grids[nuc*n_gridpoints + idx]; - } - else if( grid_type == UNIONIZED) // Unionized Energy Grid - we already know the index, no binary search needed. - { - // pull ptr from energy grid and check to ensure that - // we're not reading off the end of the nuclide's grid - if( index_data[idx * n_isotopes + nuc] == n_gridpoints - 1 ) - low = &nuclide_grids[nuc*n_gridpoints + index_data[idx * n_isotopes + nuc] - 1]; - else - low = &nuclide_grids[nuc*n_gridpoints + index_data[idx * n_isotopes + nuc]]; - } - else // Hash grid - { - // load lower bounding index - int u_low = index_data[idx * n_isotopes + nuc]; - - // Determine higher bounding index - int u_high; - if( idx == hash_bins - 1 ) - u_high = n_gridpoints - 1; - else - u_high = index_data[(idx+1)*n_isotopes + nuc] + 1; - - // Check edge cases to make sure energy is actually between these - // Then, if things look good, search for gridpoint in the nuclide grid - // within the lower and higher limits we've calculated. - double e_low = nuclide_grids[nuc*n_gridpoints + u_low].energy; - double e_high = nuclide_grids[nuc*n_gridpoints + u_high].energy; - int lower; - if( p_energy <= e_low ) - lower = 0; - else if( p_energy >= e_high ) - lower = n_gridpoints - 1; - else - lower = grid_search_nuclide( n_gridpoints, p_energy, &nuclide_grids[nuc*n_gridpoints], u_low, u_high); - - if( lower == n_gridpoints - 1 ) - low = &nuclide_grids[nuc*n_gridpoints + lower - 1]; - else - low = &nuclide_grids[nuc*n_gridpoints + lower]; - } - - high = low + 1; - - // calculate the re-useable interpolation factor - f = (high->energy - p_energy) / (high->energy - low->energy); - - // Total XS - xs_vector[0] = high->total_xs - f * (high->total_xs - low->total_xs); - - // Elastic XS - xs_vector[1] = high->elastic_xs - f * (high->elastic_xs - low->elastic_xs); - - // Absorbtion XS - xs_vector[2] = high->absorbtion_xs - f * (high->absorbtion_xs - low->absorbtion_xs); - - // Fission XS - xs_vector[3] = high->fission_xs - f * (high->fission_xs - low->fission_xs); - - // Nu Fission XS - xs_vector[4] = high->nu_fission_xs - f * (high->nu_fission_xs - low->nu_fission_xs); -} - -// Calculates macroscopic cross section based on a given material & energy -void calculate_macro_xs( double p_energy, int mat, long n_isotopes, - long n_gridpoints, int * restrict num_nucs, - double * restrict concs, - double * restrict egrid, int * restrict index_data, - NuclideGridPoint * restrict nuclide_grids, - int * restrict mats, - double * restrict macro_xs_vector, int grid_type, int hash_bins, int max_num_nucs ){ - int p_nuc; // the nuclide we are looking up - long idx = -1; - double conc; // the concentration of the nuclide in the material - - // cleans out macro_xs_vector - for( int k = 0; k < 5; k++ ) - macro_xs_vector[k] = 0; - - // If we are using the unionized energy grid (UEG), we only - // need to perform 1 binary search per macroscopic lookup. - // If we are using the nuclide grid search, it will have to be - // done inside of the "calculate_micro_xs" function for each different - // nuclide in the material. - if( grid_type == UNIONIZED ) - idx = grid_search( n_isotopes * n_gridpoints, p_energy, egrid); - else if( grid_type == HASH ) - { - double du = 1.0 / hash_bins; - idx = p_energy / du; - } - - // Once we find the pointer array on the UEG, we can pull the data - // from the respective nuclide grids, as well as the nuclide - // concentration data for the material - // Each nuclide from the material needs to have its micro-XS array - // looked up & interpolatied (via calculate_micro_xs). Then, the - // micro XS is multiplied by the concentration of that nuclide - // in the material, and added to the total macro XS array. - // (Independent -- though if parallelizing, must use atomic operations - // or otherwise control access to the xs_vector and macro_xs_vector to - // avoid simulataneous writing to the same data structure) - for( int j = 0; j < num_nucs[mat]; j++ ) - { - double xs_vector[5]; - p_nuc = mats[mat*max_num_nucs + j]; - conc = concs[mat*max_num_nucs + j]; - calculate_micro_xs( p_energy, p_nuc, n_isotopes, - n_gridpoints, egrid, index_data, - nuclide_grids, idx, xs_vector, grid_type, hash_bins ); - for( int k = 0; k < 5; k++ ) - macro_xs_vector[k] += xs_vector[k] * conc; - } -} - - -// binary search for energy on unionized energy grid -// returns lower index -long grid_search( long n, double quarry, double * restrict A) -{ - long lowerLimit = 0; - long upperLimit = n-1; - long examinationPoint; - long length = upperLimit - lowerLimit; - - while( length > 1 ) - { - examinationPoint = lowerLimit + ( length / 2 ); - - if( A[examinationPoint] > quarry ) - upperLimit = examinationPoint; - else - lowerLimit = examinationPoint; - - length = upperLimit - lowerLimit; - } - - return lowerLimit; -} - -// binary search for energy on nuclide energy grid -long grid_search_nuclide( long n, double quarry, NuclideGridPoint * A, long low, long high) -{ - long lowerLimit = low; - long upperLimit = high; - long examinationPoint; - long length = upperLimit - lowerLimit; - - while( length > 1 ) - { - examinationPoint = lowerLimit + ( length / 2 ); - - if( A[examinationPoint].energy > quarry ) - upperLimit = examinationPoint; - else - lowerLimit = examinationPoint; - - length = upperLimit - lowerLimit; - } - - return lowerLimit; -} - -// picks a material based on a probabilistic distribution -int pick_mat( uint64_t * seed ) -{ - // I have a nice spreadsheet supporting these numbers. They are - // the fractions (by volume) of material in the core. Not a - // *perfect* approximation of where XS lookups are going to occur, - // but this will do a good job of biasing the system nonetheless. - - double dist[12]; - dist[0] = 0.140; // fuel - dist[1] = 0.052; // cladding - dist[2] = 0.275; // cold, borated water - dist[3] = 0.134; // hot, borated water - dist[4] = 0.154; // RPV - dist[5] = 0.064; // Lower, radial reflector - dist[6] = 0.066; // Upper reflector / top plate - dist[7] = 0.055; // bottom plate - dist[8] = 0.008; // bottom nozzle - dist[9] = 0.015; // top nozzle - dist[10] = 0.025; // top of fuel assemblies - dist[11] = 0.013; // bottom of fuel assemblies - - double roll = LCG_random_double(seed); - - // makes a pick based on the distro - for( int i = 0; i < 12; i++ ) - { - double running = 0; - for( int j = i; j > 0; j-- ) - running += dist[j]; - if( roll < running ) - return i; - } - - return 0; -} - -double LCG_random_double(uint64_t * seed) -{ - // LCG parameters - const uint64_t m = 9223372036854775808ULL; // 2^63 - const uint64_t a = 2806196910506780709ULL; - const uint64_t c = 1ULL; - *seed = (a * (*seed) + c) % m; - return (double) (*seed) / (double) m; -} - -uint64_t fast_forward_LCG(uint64_t seed, uint64_t n) -{ - // LCG parameters - const uint64_t m = 9223372036854775808ULL; // 2^63 - uint64_t a = 2806196910506780709ULL; - uint64_t c = 1ULL; - - n = n % m; - - uint64_t a_new = 1; - uint64_t c_new = 0; - - while(n > 0) - { - if(n & 1) - { - a_new *= a; - c_new = c_new * a + c; - } - c *= (a + 1); - a *= a; - - n >>= 1; - } - - return (a_new * seed + c_new) % m; - -} - -//////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////// -// OPTIMIZED VARIANT FUNCTIONS -//////////////////////////////////////////////////////////////////////////////////// -// This section contains a number of optimized variants of some of the above -// functions, which each deploy a different combination of optimizations strategies. -// By default, XSBench will not run any of these variants. They -// must be specifically selected using the "-k " command -// line argument. -// -// As fast parallel sorting will be required for these optimizations, we will -// first define a set of key-value parallel quicksort routines. -//////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////////////////////////////// -// Parallel Quicksort Key-Value Sorting Algorithms -//////////////////////////////////////////////////////////////////////////////////// -// -// These algorithms are based on the parallel quicksort implementation by -// Eduard Lopez published at https://github.com/eduardlopez/quicksort-parallel -// -// Eduard's original version was for an integer type quicksort, but I have modified -// it to form two different versions that can sort key-value pairs together without -// having to bundle them into a separate object. Additionally, I have modified the -// optimal chunk sizes and restricted the number of threads for the array sizing -// that XSBench will be using by default. -// -// Eduard's original implementation carries the following license, which applies to -// the following functions only: -// -// void quickSort_parallel_internal_i_d(int* key,double * value, int left, int right, int cutoff) -// void quickSort_parallel_i_d(int* key,double * value, int lenArray, int numThreads) -// void quickSort_parallel_internal_d_i(double* key,int * value, int left, int right, int cutoff) -// void quickSort_parallel_d_i(double* key,int * value, int lenArray, int numThreads) -// -// The MIT License (MIT) -// -// Copyright (c) 2016 Eduard López -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -//////////////////////////////////////////////////////////////////////////////////// -void quickSort_parallel_internal_i_d(int* key,double * value, int left, int right, int cutoff) -{ - int i = left, j = right; - int tmp; - int pivot = key[(left + right) / 2]; - - { - while (i <= j) { - while (key[i] < pivot) - i++; - while (key[j] > pivot) - j--; - if (i <= j) { - tmp = key[i]; - key[i] = key[j]; - key[j] = tmp; - double tmp_v = value[i]; - value[i] = value[j]; - value[j] = tmp_v; - i++; - j--; - } - } - - } - - if ( ((right-left) 16 ) - numThreads = 16; - - #pragma omp parallel num_threads(numThreads) - { - #pragma omp single nowait - { - quickSort_parallel_internal_i_d(key,value, 0, lenArray-1, cutoff); - } - } - -} - -void quickSort_parallel_internal_d_i(double* key,int * value, int left, int right, int cutoff) -{ - int i = left, j = right; - double tmp; - double pivot = key[(left + right) / 2]; - - { - while (i <= j) { - while (key[i] < pivot) - i++; - while (key[j] > pivot) - j--; - if (i <= j) { - tmp = key[i]; - key[i] = key[j]; - key[j] = tmp; - int tmp_v = value[i]; - value[i] = value[j]; - value[j] = tmp_v; - i++; - j--; - } - } - - } - - if ( ((right-left) 16 ) - numThreads = 16; - - #pragma omp parallel num_threads(numThreads) - { - #pragma omp single nowait - { - quickSort_parallel_internal_d_i(key,value, 0, lenArray-1, cutoff); - } - } - -} - -//////////////////////////////////////////////////////////////////////////////////// -// Optimization 1 -- Event-based Sample/XS Lookup kernel splitting + Sorting -// lookups by material and energy -//////////////////////////////////////////////////////////////////////////////////// -// This kernel separates out the sampling and lookup regions of the event-based -// model, and then sorts the lookups by material type and energy. The goal of this -// optimization is to allow for greatly improved cache locality, and XS indices -// loaded from memory may be re-used for multiple lookups. -// -// As efficienct sorting is key for performance, we also must implement an -// efficient key-value parallel sorting algorithm. We also experimented with using -// the C++ version of thrust for these purposes, but found that our own implemtation -// was slightly faster than the thrust library version, so for speed and -// simplicity we will do not add the thrust dependency. -//////////////////////////////////////////////////////////////////////////////////// - - -unsigned long long run_event_based_simulation_optimization_1(Inputs in, SimulationData SD, int mype) -{ - char * optimization_name = "Optimization 1 - Kernel splitting + full material & energy sort"; - - if( mype == 0) printf("Simulation Kernel:\"%s\"\n", optimization_name); - - //////////////////////////////////////////////////////////////////////////////// - // Allocate Additional Data Structures Needed by Optimized Kernel - //////////////////////////////////////////////////////////////////////////////// - if( mype == 0) printf("Allocating additional data required by optimized kernel...\n"); - size_t sz; - size_t total_sz = 0; - double start, stop; - - // loop variables - int i = 0; - int m = 0; - - sz = in.lookups * sizeof(double); - SD.p_energy_samples = (double *) malloc(sz); - total_sz += sz; - SD.length_p_energy_samples = in.lookups; - - sz = in.lookups * sizeof(int); - SD.mat_samples = (int *) malloc(sz); - total_sz += sz; - SD.length_mat_samples = in.lookups; - - if( mype == 0) printf("Allocated an additional %.0lf MB of data on GPU.\n", total_sz/1024.0/1024.0); - - //////////////////////////////////////////////////////////////////////////////// - // Begin Actual Simulation - //////////////////////////////////////////////////////////////////////////////// - - //////////////////////////////////////////////////////////////////////////////// - // Sample Materials and Energies - //////////////////////////////////////////////////////////////////////////////// - #pragma omp parallel for schedule(dynamic, 100) - for( i = 0; i < in.lookups; i++ ) - { - // Set the initial seed value - uint64_t seed = STARTING_SEED; - - // Forward seed to lookup index (we need 2 samples per lookup) - seed = fast_forward_LCG(seed, 2*i); - - // Randomly pick an energy and material for the particle - double p_energy = LCG_random_double(&seed); - int mat = pick_mat(&seed); - - SD.p_energy_samples[i] = p_energy; - SD.mat_samples[i] = mat; - } - if(mype == 0) printf("finished sampling...\n"); - - //////////////////////////////////////////////////////////////////////////////// - // Sort by Material - //////////////////////////////////////////////////////////////////////////////// - - start = get_time(); - - quickSort_parallel_i_d(SD.mat_samples, SD.p_energy_samples, in.lookups, in.nthreads); - - stop = get_time(); - - if(mype == 0) printf("Material sort took %.3lf seconds\n", stop-start); - - //////////////////////////////////////////////////////////////////////////////// - // Sort by Energy - //////////////////////////////////////////////////////////////////////////////// - - start = get_time(); - - // Count up number of each type of sample. - int num_samples_per_mat[12] = {0}; - for( int l = 0; l < in.lookups; l++ ) - num_samples_per_mat[ SD.mat_samples[l] ]++; - - // Determine offsets - int offsets[12] = {0}; - for( int m = 1; m < 12; m++ ) - offsets[m] = offsets[m-1] + num_samples_per_mat[m-1]; - - stop = get_time(); - if(mype == 0) printf("Counting samples and offsets took %.3lf seconds\n", stop-start); - start = stop; - - // Sort each material type by energy level - int offset = 0; - for( int m = 0; m < 12; m++ ) - quickSort_parallel_d_i(SD.p_energy_samples + offsets[m],SD.mat_samples + offsets[m], num_samples_per_mat[m], in.nthreads); - - stop = get_time(); - if(mype == 0) printf("Energy Sorts took %.3lf seconds\n", stop-start); - - //////////////////////////////////////////////////////////////////////////////// - // Perform lookups for each material separately - //////////////////////////////////////////////////////////////////////////////// - start = get_time(); - - unsigned long long verification = 0; - - // Individual Materials - offset = 0; - for( m = 0; m < 12; m++ ) - { - #pragma omp parallel for schedule(dynamic,100) reduction(+:verification) - for( i = offset; i < offset + num_samples_per_mat[m]; i++) - { - #ifdef AML - int * num_nucs = aml_replicaset_hwloc_local_replica(SD.num_nucs_replica); - double * concs = aml_replicaset_hwloc_local_replica(SD.concs_replica); - double * unionized_energy_array = aml_replicaset_hwloc_local_replica(SD.unionized_energy_array_replica); - int * index_grid = aml_replicaset_hwloc_local_replica(SD.index_grid_replica); - NuclideGridPoint * nuclide_grid = aml_replicaset_hwloc_local_replica(SD.nuclide_grid_replica); - #else - int * num_nucs = SD.num_nucs; - double * concs = SD.concs; - double * unionized_energy_array = SD.unionized_energy_array; - int * index_grid = SD.index_grid; - NuclideGridPoint * nuclide_grid = SD.nuclide_grid; - #endif - - // load pre-sampled energy and material for the particle - double p_energy = SD.p_energy_samples[i]; - int mat = SD.mat_samples[i]; - - double macro_xs_vector[5] = {0}; - - // Perform macroscopic Cross Section Lookup - calculate_macro_xs( - p_energy, // Sampled neutron energy (in lethargy) - mat, // Sampled material type index neutron is in - in.n_isotopes, // Total number of isotopes in simulation - in.n_gridpoints, // Number of gridpoints per isotope in simulation - num_nucs, // 1-D array with number of nuclides per material - concs, // Flattened 2-D array with concentration of each nuclide in each material - unionized_energy_array, // 1-D Unionized energy array - index_grid, // Flattened 2-D grid holding indices into nuclide grid for each unionized energy level - nuclide_grid, // Flattened 2-D grid holding energy levels and XS_data for all nuclides in simulation - SD.mats, // Flattened 2-D array with nuclide indices defining composition of each type of material - macro_xs_vector, // 1-D array with result of the macroscopic cross section (5 different reaction channels) - in.grid_type, // Lookup type (nuclide, hash, or unionized) - in.hash_bins, // Number of hash bins used (if using hash lookup type) - SD.max_num_nucs // Maximum number of nuclides present in any material - ); - - // For verification, and to prevent the compiler from optimizing - // all work out, we interrogate the returned macro_xs_vector array - // to find its maximum value index, then increment the verification - // value by that index. In this implementation, we prevent thread - // contention by using an OMP reduction on the verification value. - // For accelerators, a different approach might be required - // (e.g., atomics, reduction of thread-specific values in large - // array via CUDA thrust, etc). - double max = -1.0; - int max_idx = 0; - for(int j = 0; j < 5; j++ ) - { - if( macro_xs_vector[j] > max ) - { - max = macro_xs_vector[j]; - max_idx = j; - } - } - verification += max_idx+1; - } - offset += num_samples_per_mat[m]; - } - - stop = get_time(); - if(mype == 0) printf("XS Lookups took %.3lf seconds\n", stop-start); - return verification; -} \ No newline at end of file diff --git a/benchmarks/benchmarks/XSbench/XSbench_header.h b/benchmarks/benchmarks/XSbench/XSbench_header.h deleted file mode 100644 index a0229ed..0000000 --- a/benchmarks/benchmarks/XSbench/XSbench_header.h +++ /dev/null @@ -1,151 +0,0 @@ -#ifndef __XSBENCH_HEADER_H__ -#define __XSBENCH_HEADER_H__ - -#include -#include -#include -#include -#include -#include -#include - -#ifdef _MSC_VER -#define strncasecmp _strnicmp -#define strcasecmp _stricmp -#else -#include -#include -#endif - -#ifdef OPENMP -#include -#endif - -// Papi Header -#ifdef PAPI -#include "papi.h" -#endif - -//AML header -#ifdef AML -#include -#include -#include -#endif - -// Grid types -#define UNIONIZED 0 -#define NUCLIDE 1 -#define HASH 2 - -// Simulation types -#define HISTORY_BASED 1 -#define EVENT_BASED 2 - -// Binary Mode Type -#define NONE 0 -#define READ 1 -#define WRITE 2 - -// Starting Seed -#define STARTING_SEED 1070 - -// Structures -typedef struct{ - double energy; - double total_xs; - double elastic_xs; - double absorbtion_xs; - double fission_xs; - double nu_fission_xs; -} NuclideGridPoint; - -typedef struct{ - int nthreads; - long n_isotopes; - long n_gridpoints; - int lookups; - char * HM; - int grid_type; // 0: Unionized Grid (default) 1: Nuclide Grid - int hash_bins; - int particles; - int simulation_method; - int binary_mode; - int kernel_id; -} Inputs; - -typedef struct{ - int * num_nucs; // Length = length_num_nucs; - double * concs; // Length = length_concs - int * mats; // Length = length_mats - double * unionized_energy_array; // Length = length_unionized_energy_array - int * index_grid; // Length = length_index_grid - NuclideGridPoint * nuclide_grid; // Length = length_nuclide_grid -#ifdef AML - struct aml_replicaset * num_nucs_replica; - struct aml_replicaset * concs_replica; - struct aml_replicaset * unionized_energy_array_replica; - struct aml_replicaset * index_grid_replica; - struct aml_replicaset * nuclide_grid_replica; -#endif - int length_num_nucs; - int length_concs; - int length_mats; - int length_unionized_energy_array; - long length_index_grid; - int length_nuclide_grid; - int max_num_nucs; - double * p_energy_samples; - int length_p_energy_samples; - int * mat_samples; - int length_mat_samples; -} SimulationData; - -// io.c -void logo(int version); -void center_print(const char *s, int width); -void border_print(void); -void fancy_int(long a); -Inputs read_CLI( int argc, char * argv[] ); -void print_CLI_error(void); -void print_inputs(Inputs in, int nprocs, int version); -int print_results( Inputs in, int mype, double runtime, int nprocs, unsigned long long vhash ); -void binary_write( Inputs in, SimulationData SD ); -SimulationData binary_read( Inputs in ); - -// Simulation.c -unsigned long long run_event_based_simulation(Inputs in, SimulationData SD, int mype); -unsigned long long run_history_based_simulation(Inputs in, SimulationData SD, int mype); -void calculate_micro_xs( double p_energy, int nuc, long n_isotopes, - long n_gridpoints, - double * restrict egrid, int * restrict index_data, - NuclideGridPoint * restrict nuclide_grids, - long idx, double * restrict xs_vector, int grid_type, int hash_bins ); -void calculate_macro_xs( double p_energy, int mat, long n_isotopes, - long n_gridpoints, int * restrict num_nucs, - double * restrict concs, - double * restrict egrid, int * restrict index_data, - NuclideGridPoint * restrict nuclide_grids, - int * restrict mats, - double * restrict macro_xs_vector, int grid_type, int hash_bins, int max_num_nucs ); -long grid_search( long n, double quarry, double * restrict A); -long grid_search_nuclide( long n, double quarry, NuclideGridPoint * A, long low, long high); -int pick_mat( uint64_t * seed ); -double LCG_random_double(uint64_t * seed); -uint64_t fast_forward_LCG(uint64_t seed, uint64_t n); -unsigned long long run_event_based_simulation_optimization_1(Inputs in, SimulationData SD, int mype); - -// GridInit.c -SimulationData grid_init_do_not_profile( Inputs in, int mype ); - -// XSutils.c -int NGP_compare( const void * a, const void * b ); -int double_compare(const void * a, const void * b); -size_t estimate_mem_usage( Inputs in ); -double get_time(void); - -// Materials.c -int * load_num_nucs(long n_isotopes); -int * load_mats( int * num_nucs, long n_isotopes, int * max_num_nucs ); -double * load_concs( int * num_nucs, int max_num_nucs ); -#endif \ No newline at end of file diff --git a/benchmarks/benchmarks/XSbench/XSutils.c b/benchmarks/benchmarks/XSbench/XSutils.c deleted file mode 100644 index 72984c1..0000000 --- a/benchmarks/benchmarks/XSbench/XSutils.c +++ /dev/null @@ -1,63 +0,0 @@ -#include "XSbench_header.h" - -int double_compare(const void * a, const void * b) -{ - double A = *((double *) a); - double B = *((double *) b); - - if( A > B ) - return 1; - else if( A < B ) - return -1; - else - return 0; -} - -int NGP_compare(const void * a, const void * b) -{ - NuclideGridPoint A = *((NuclideGridPoint *) a); - NuclideGridPoint B = *((NuclideGridPoint *) b); - - if( A.energy > B.energy ) - return 1; - else if( A.energy < B.energy ) - return -1; - else - return 0; -} - - -size_t estimate_mem_usage( Inputs in ) -{ - size_t single_nuclide_grid = in.n_gridpoints * sizeof( NuclideGridPoint ); - size_t all_nuclide_grids = in.n_isotopes * single_nuclide_grid; - size_t size_UEG = in.n_isotopes*in.n_gridpoints*sizeof(double) + in.n_isotopes*in.n_gridpoints*in.n_isotopes*sizeof(int); - size_t size_hash_grid = in.hash_bins * in.n_isotopes * sizeof(int); - size_t memtotal; - - if( in.grid_type == UNIONIZED ) - memtotal = all_nuclide_grids + size_UEG; - else if( in.grid_type == NUCLIDE ) - memtotal = all_nuclide_grids; - else - memtotal = all_nuclide_grids + size_hash_grid; - - memtotal = ceil(memtotal / (1024.0*1024.0)); - return memtotal; -} - -double get_time(void) -{ - #ifdef OPENMP - return omp_get_wtime(); - #endif - - struct timeval timecheck; - - gettimeofday(&timecheck, NULL); - long ms = (long)timecheck.tv_sec * 1000 + (long)timecheck.tv_usec / 1000; - - double time = (double) ms / 1000.0; - - return time; -} \ No newline at end of file diff --git a/benchmarks/benchmarks/XSbench/io.c b/benchmarks/benchmarks/XSbench/io.c deleted file mode 100644 index f8b85c3..0000000 --- a/benchmarks/benchmarks/XSbench/io.c +++ /dev/null @@ -1,508 +0,0 @@ -#include "XSbench_header.h" - -#ifdef MPI -#include -#endif - -// Prints program logo -void logo(int version) -{ - border_print(); - printf( - " __ __ ___________ _ \n" - " \\ \\ / // ___| ___ \\ | | \n" - " \\ V / \\ `--.| |_/ / ___ _ __ ___| |__ \n" - " / \\ `--. \\ ___ \\/ _ \\ '_ \\ / __| '_ \\ \n" - " / /^\\ \\/\\__/ / |_/ / __/ | | | (__| | | | \n" - " \\/ \\/\\____/\\____/ \\___|_| |_|\\___|_| |_| \n\n" - ); - border_print(); - center_print("Developed at Argonne National Laboratory", 79); - char v[100]; - sprintf(v, "Version: %d", version); - center_print(v, 79); - border_print(); -} - -// Prints Section titles in center of 80 char terminal -void center_print(const char *s, int width) -{ - int length = strlen(s); - int i; - for (i=0; i<=(width-length)/2; i++) { - fputs(" ", stdout); - } - fputs(s, stdout); - fputs("\n", stdout); -} - -int print_results( Inputs in, int mype, double runtime, int nprocs, - unsigned long long vhash ) -{ - // Calculate Lookups per sec - int lookups = 0; - if( in.simulation_method == HISTORY_BASED ) - lookups = in.lookups * in.particles; - else if( in.simulation_method == EVENT_BASED ) - lookups = in.lookups; - int lookups_per_sec = (int) ((double) lookups / runtime); - - // If running in MPI, reduce timing statistics and calculate average - #ifdef MPI - int total_lookups = 0; - MPI_Barrier(MPI_COMM_WORLD); - MPI_Reduce(&lookups_per_sec, &total_lookups, 1, MPI_INT, - MPI_SUM, 0, MPI_COMM_WORLD); - #endif - - int is_invalid_result = 1; - - // Print output - if( mype == 0 ) - { - border_print(); - center_print("RESULTS", 79); - border_print(); - - // Print the results - printf("Threads: %d\n", in.nthreads); - #ifdef MPI - printf("MPI ranks: %d\n", nprocs); - #endif - #ifdef MPI - printf("Total Lookups/s: "); - fancy_int(total_lookups); - printf("Avg Lookups/s per MPI rank: "); - fancy_int(total_lookups / nprocs); - #else - printf("Runtime: %.3lf seconds\n", runtime); - printf("Lookups: "); fancy_int(lookups); - printf("Lookups/s: "); - fancy_int(lookups_per_sec); - #endif - } - - unsigned long long large = 0; - unsigned long long small = 0; - if( in.simulation_method == EVENT_BASED ) - { - small = 945990; - large = 952131; - } - else if( in.simulation_method == HISTORY_BASED ) - { - small = 941535; - large = 954318; - } - if( strcmp(in.HM, "large") == 0 ) - { - if( vhash == large ) - is_invalid_result = 0; - } - else if( strcmp(in.HM, "small") == 0 ) - { - if( vhash == small ) - is_invalid_result = 0; - } - - if(mype == 0 ) - { - if( is_invalid_result ) - printf("Verification checksum: %llu (WARNING - INVALID CHECKSUM!)\n", vhash); - else - printf("Verification checksum: %llu (Valid)\n", vhash); - border_print(); - } - - return is_invalid_result; -} - -void print_inputs(Inputs in, int nprocs, int version ) -{ - // Calculate Estimate of Memory Usage - int mem_tot = estimate_mem_usage( in ); - logo(version); - center_print("INPUT SUMMARY", 79); - border_print(); - if( in.simulation_method == EVENT_BASED ) - printf("Simulation Method: Event Based\n"); - else - printf("Simulation Method: History Based\n"); - if( in.grid_type == NUCLIDE ) - printf("Grid Type: Nuclide Grid\n"); - else if( in.grid_type == UNIONIZED ) - printf("Grid Type: Unionized Grid\n"); - else - printf("Grid Type: Hash\n"); - - printf("Materials: %d\n", 12); - printf("H-M Benchmark Size: %s\n", in.HM); - printf("Total Nuclides: %ld\n", in.n_isotopes); - printf("Gridpoints (per Nuclide): "); - fancy_int(in.n_gridpoints); - if( in.grid_type == HASH ) - { - printf("Hash Bins: "); - fancy_int(in.hash_bins); - } - if( in.grid_type == UNIONIZED ) - { - printf("Unionized Energy Gridpoints: "); - fancy_int(in.n_isotopes*in.n_gridpoints); - } - if( in.simulation_method == HISTORY_BASED ) - { - printf("Particle Histories: "); fancy_int(in.particles); - printf("XS Lookups per Particle: "); fancy_int(in.lookups); - } - printf("Total XS Lookups: "); fancy_int(in.lookups); - #ifdef MPI - printf("MPI Ranks: %d\n", nprocs); - printf("OMP Threads per MPI Rank: %d\n", in.nthreads); - printf("Mem Usage per MPI Rank (MB): "); fancy_int(mem_tot); - #else - printf("Threads: %d\n", in.nthreads); - printf("Est. Memory Usage (MB): "); fancy_int(mem_tot); - #endif - printf("Binary File Mode: "); - if( in.binary_mode == NONE ) - printf("Off\n"); - else if( in.binary_mode == READ) - printf("Read\n"); - else - printf("Write\n"); - border_print(); - center_print("INITIALIZATION - DO NOT PROFILE", 79); - border_print(); -} - -void border_print(void) -{ - printf( - "===================================================================" - "=============\n"); -} - -// Prints comma separated integers - for ease of reading -void fancy_int( long a ) -{ - if( a < 1000 ) - printf("%ld\n",a); - - else if( a >= 1000 && a < 1000000 ) - printf("%ld,%03ld\n", a / 1000, a % 1000); - - else if( a >= 1000000 && a < 1000000000 ) - printf("%ld,%03ld,%03ld\n",a / 1000000,(a % 1000000) / 1000,a % 1000 ); - - else if( a >= 1000000000 ) - printf("%ld,%03ld,%03ld,%03ld\n", - a / 1000000000, - (a % 1000000000) / 1000000, - (a % 1000000) / 1000, - a % 1000 ); - else - printf("%ld\n",a); -} - -void print_CLI_error(void) -{ - printf("Usage: ./XSBench \n"); - printf("Options include:\n"); - printf(" -m Simulation method (history, event)\n"); - printf(" -t Number of OpenMP threads to run\n"); - printf(" -s Size of H-M Benchmark to run (small, large, XL, XXL)\n"); - printf(" -g Number of gridpoints per nuclide (overrides -s defaults)\n"); - printf(" -G Grid search type (unionized, nuclide, hash). Defaults to unionized.\n"); - printf(" -p Number of particle histories\n"); - printf(" -l History Based: Number of Cross-section (XS) lookups per particle. Event Based: Total number of XS lookups.\n"); - printf(" -h Number of hash bins (only relevant when used with \"-G hash\")\n"); - printf(" -b Read or write all data structures to file. If reading, this will skip initialization phase. (read, write)\n"); - printf(" -k Specifies which kernel to run. 0 is baseline, 1, 2, etc are optimized variants. (0 is default.)\n"); - printf("Default is equivalent to: -m history -s large -l 34 -p 500000 -G unionized\n"); - printf("See readme for full description of default run values\n"); - exit(4); -} - -Inputs read_CLI( int argc, char * argv[] ) -{ - Inputs input; - - // defaults to the history based simulation method - input.simulation_method = HISTORY_BASED; - - // defaults to max threads on the system - #ifdef OPENMP - input.nthreads = omp_get_num_procs(); - #else - input.nthreads = 1; - #endif - - // defaults to 355 (corresponding to H-M Large benchmark) - input.n_isotopes = 355; - - // defaults to 11303 (corresponding to H-M Large benchmark) - input.n_gridpoints = 11303; - - // defaults to 500,000 - input.particles = 500000; - - // defaults to 34 - input.lookups = 34; - - // default to unionized grid - input.grid_type = UNIONIZED; - - // default to unionized grid - input.hash_bins = 10000; - - // default to no binary read/write - input.binary_mode = NONE; - - // defaults to baseline kernel - input.kernel_id = 0; - - // defaults to H-M Large benchmark - input.HM = (char *) malloc( 6 * sizeof(char) ); - input.HM[0] = 'l' ; - input.HM[1] = 'a' ; - input.HM[2] = 'r' ; - input.HM[3] = 'g' ; - input.HM[4] = 'e' ; - input.HM[5] = '\0'; - - // Check if user sets these - int user_g = 0; - - int default_lookups = 1; - int default_particles = 1; - - // Collect Raw Input - for( int i = 1; i < argc; i++ ) - { - char * arg = argv[i]; - - // nthreads (-t) - if( strcmp(arg, "-t") == 0 ) - { - if( ++i < argc ) - input.nthreads = atoi(argv[i]); - else - print_CLI_error(); - } - // n_gridpoints (-g) - else if( strcmp(arg, "-g") == 0 ) - { - if( ++i < argc ) - { - user_g = 1; - input.n_gridpoints = atol(argv[i]); - } - else - print_CLI_error(); - } - // Simulation Method (-m) - else if( strcmp(arg, "-m") == 0 ) - { - char * sim_type; - if( ++i < argc ) - sim_type = argv[i]; - else - print_CLI_error(); - - if( strcmp(sim_type, "history") == 0 ) - input.simulation_method = HISTORY_BASED; - else if( strcmp(sim_type, "event") == 0 ) - { - input.simulation_method = EVENT_BASED; - // Also resets default # of lookups - if( default_lookups && default_particles ) - { - input.lookups = input.lookups * input.particles; - input.particles = 0; - } - } - else - print_CLI_error(); - } - // lookups (-l) - else if( strcmp(arg, "-l") == 0 ) - { - if( ++i < argc ) - { - input.lookups = atoi(argv[i]); - default_lookups = 0; - } - else - print_CLI_error(); - } - // hash bins (-h) - else if( strcmp(arg, "-h") == 0 ) - { - if( ++i < argc ) - input.hash_bins = atoi(argv[i]); - else - print_CLI_error(); - } - // particles (-p) - else if( strcmp(arg, "-p") == 0 ) - { - if( ++i < argc ) - { - input.particles = atoi(argv[i]); - default_particles = 0; - } - else - print_CLI_error(); - } - // HM (-s) - else if( strcmp(arg, "-s") == 0 ) - { - if( ++i < argc ) - input.HM = argv[i]; - else - print_CLI_error(); - } - // grid type (-G) - else if( strcmp(arg, "-G") == 0 ) - { - char * grid_type; - if( ++i < argc ) - grid_type = argv[i]; - else - print_CLI_error(); - - if( strcmp(grid_type, "unionized") == 0 ) - input.grid_type = UNIONIZED; - else if( strcmp(grid_type, "nuclide") == 0 ) - input.grid_type = NUCLIDE; - else if( strcmp(grid_type, "hash") == 0 ) - input.grid_type = HASH; - else - print_CLI_error(); - } - // binary mode (-b) - else if( strcmp(arg, "-b") == 0 ) - { - char * binary_mode; - if( ++i < argc ) - binary_mode = argv[i]; - else - print_CLI_error(); - - if( strcmp(binary_mode, "read") == 0 ) - input.binary_mode = READ; - else if( strcmp(binary_mode, "write") == 0 ) - input.binary_mode = WRITE; - else - print_CLI_error(); - } - // kernel optimization selection (-k) - else if( strcmp(arg, "-k") == 0 ) - { - if( ++i < argc ) - { - input.kernel_id = atoi(argv[i]); - } - else - print_CLI_error(); - } - else - print_CLI_error(); - } - - // Validate Input - - // Validate nthreads - if( input.nthreads < 1 ) - print_CLI_error(); - - // Validate n_isotopes - if( input.n_isotopes < 1 ) - print_CLI_error(); - - // Validate n_gridpoints - if( input.n_gridpoints < 1 ) - print_CLI_error(); - - // Validate lookups - if( input.lookups < 1 ) - print_CLI_error(); - - // Validate Hash Bins - if( input.hash_bins < 1 ) - print_CLI_error(); - - // Validate HM size - if( strcasecmp(input.HM, "small") != 0 && - strcasecmp(input.HM, "large") != 0 && - strcasecmp(input.HM, "XL") != 0 && - strcasecmp(input.HM, "XXL") != 0 ) - print_CLI_error(); - - // Set HM size specific parameters - // (defaults to large) - if( strcasecmp(input.HM, "small") == 0 ) - input.n_isotopes = 68; - else if( strcasecmp(input.HM, "XL") == 0 && user_g == 0 ) - input.n_gridpoints = 238847; // sized to make 120 GB XS data - else if( strcasecmp(input.HM, "XXL") == 0 && user_g == 0 ) - input.n_gridpoints = 238847 * 2.1; // 252 GB XS data - - // Return input struct - return input; -} - -void binary_write( Inputs in, SimulationData SD ) -{ - char * fname = "XS_data.dat"; - printf("Writing all data structures to binary file %s...\n", fname); - FILE * fp = fopen(fname, "w"); - - // Write SimulationData Object. Include pointers, even though we won't be using them. - fwrite(&SD, sizeof(SimulationData), 1, fp); - - // Write heap arrays in SimulationData Object - fwrite(SD.num_nucs, sizeof(int), SD.length_num_nucs, fp); - fwrite(SD.concs, sizeof(double), SD.length_concs, fp); - fwrite(SD.mats, sizeof(int), SD.length_mats, fp); - fwrite(SD.nuclide_grid, sizeof(NuclideGridPoint), SD.length_nuclide_grid, fp); - fwrite(SD.index_grid, sizeof(int), SD.length_index_grid, fp); - fwrite(SD.unionized_energy_array, sizeof(double), SD.length_unionized_energy_array, fp); - - fclose(fp); -} - -SimulationData binary_read( Inputs in ) -{ - SimulationData SD; - - char * fname = "XS_data.dat"; - printf("Reading all data structures from binary file %s...\n", fname); - - FILE * fp = fopen(fname, "r"); - assert(fp != NULL); - - // Read SimulationData Object. Include pointers, even though we won't be using them. - fread(&SD, sizeof(SimulationData), 1, fp); - - // Allocate space for arrays on heap - SD.num_nucs = (int *) malloc(SD.length_num_nucs * sizeof(int)); - SD.concs = (double *) malloc(SD.length_concs * sizeof(double)); - SD.mats = (int *) malloc(SD.length_mats * sizeof(int)); - SD.nuclide_grid = (NuclideGridPoint *) malloc(SD.length_nuclide_grid * sizeof(NuclideGridPoint)); - SD.index_grid = (int *) malloc( SD.length_index_grid * sizeof(int)); - SD.unionized_energy_array = (double *) malloc( SD.length_unionized_energy_array * sizeof(double)); - - // Read heap arrays into SimulationData Object - fread(SD.num_nucs, sizeof(int), SD.length_num_nucs, fp); - fread(SD.concs, sizeof(double), SD.length_concs, fp); - fread(SD.mats, sizeof(int), SD.length_mats, fp); - fread(SD.nuclide_grid, sizeof(NuclideGridPoint), SD.length_nuclide_grid, fp); - fread(SD.index_grid, sizeof(int), SD.length_index_grid, fp); - fread(SD.unionized_energy_array, sizeof(double), SD.length_unionized_energy_array, fp); - - fclose(fp); - - return SD; -} \ No newline at end of file diff --git a/benchmarks/benchmarks/alloc-test/README.md b/benchmarks/benchmarks/alloc-test/README.md new file mode 100644 index 0000000..4c9a83c --- /dev/null +++ b/benchmarks/benchmarks/alloc-test/README.md @@ -0,0 +1,30 @@ +Made by OLogN Technologies and described on their +[blog](http://ithare.com/testing-memory-allocators-ptmalloc2-tcmalloc-hoard-jemalloc-while-trying-to-simulate-real-world-loads). Original repository at . + +``` +Copyright (c) 2018, OLogN Technologies AG +All rights reserved. + +* +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. +* +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +``` diff --git a/benchmarks/benchmarks/alloc-test/allocator_tester.cpp b/benchmarks/benchmarks/alloc-test/allocator_tester.cpp new file mode 100644 index 0000000..50709c7 --- /dev/null +++ b/benchmarks/benchmarks/alloc-test/allocator_tester.cpp @@ -0,0 +1,200 @@ +/* ------------------------------------------------------------------------------- + * Copyright (c) 2018, OLogN Technologies AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ------------------------------------------------------------------------------- + * + * Memory allocator tester -- main + * + * v.1.00 Jun-22-2018 Initial release + * + * -------------------------------------------------------------------------------*/ + +#include "selector.h" +#include "allocator_tester.h" + +template +void* runRandomTest( void* params ) +{ + assert( params != nullptr ); + ThreadStartupParamsAndResults* testParams = reinterpret_cast( params ); + Allocator allocator( testParams->threadRes ); + switch ( testParams->startupParams.mat ) + { + case MEM_ACCESS_TYPE::none: + randomPos_RandomSize( allocator, testParams->startupParams.iterCount, testParams->startupParams.maxItems, testParams->startupParams.maxItemSize, testParams->threadID, testParams->startupParams.rndSeed ); + break; + case MEM_ACCESS_TYPE::full: + randomPos_RandomSize( allocator, testParams->startupParams.iterCount, testParams->startupParams.maxItems, testParams->startupParams.maxItemSize, testParams->threadID, testParams->startupParams.rndSeed ); + break; + case MEM_ACCESS_TYPE::single: + randomPos_RandomSize( allocator, testParams->startupParams.iterCount, testParams->startupParams.maxItems, testParams->startupParams.maxItemSize, testParams->threadID, testParams->startupParams.rndSeed ); + break; + case MEM_ACCESS_TYPE::check: + randomPos_RandomSize( allocator, testParams->startupParams.iterCount, testParams->startupParams.maxItems, testParams->startupParams.maxItemSize, testParams->threadID, testParams->startupParams.rndSeed ); + break; + } + + return nullptr; +} + +template +void runTest( TestStartupParamsAndResults* startupParams ) +{ + size_t threadCount = startupParams->startupParams.threadCount; + + size_t start = GetMillisecondCount(); + + ThreadStartupParamsAndResults testParams[max_threads]; + std::thread threads[ max_threads ]; + + for ( size_t i=0; itestRes->threadRes + i; + } + + // run threads + for ( size_t i=0; i, (void*)(testParams + i) ); + threads[i] = std::move( t1 ); + printf( " ...done\n" ); + } + // join threads + for ( size_t i=0; itestRes->duration = end - start; + printf( "%zd threads made %zd alloc/dealloc operations in %zd ms (%zd ms per 1 million)\n", threadCount, startupParams->startupParams.iterCount * threadCount, end - start, (end - start) * 1000000 / (startupParams->startupParams.iterCount * threadCount) ); + startupParams->testRes->cumulativeDuration = 0; + startupParams->testRes->rssMax = 0; + startupParams->testRes->allocatedAfterSetupSz = 0; + startupParams->testRes->allocatedMax = 0; + for ( size_t i=0; itestRes->cumulativeDuration += startupParams->testRes->threadRes[i].innerDur; + startupParams->testRes->allocatedAfterSetupSz += startupParams->testRes->threadRes[i].allocatedAfterSetupSz; + startupParams->testRes->allocatedMax += startupParams->testRes->threadRes[i].allocatedMax; + if ( startupParams->testRes->rssMax < startupParams->testRes->threadRes[i].rssMax ) + startupParams->testRes->rssMax = startupParams->testRes->threadRes[i].rssMax; + } + startupParams->testRes->cumulativeDuration /= threadCount; + startupParams->testRes->rssAfterExitingAllThreads = getRss(); +} + +int main(int argc, char** argv) +{ + TestRes testResMyAlloc[max_threads]; + TestRes testResVoidAlloc[max_threads]; + memset( testResMyAlloc, 0, sizeof( testResMyAlloc ) ); + memset( testResVoidAlloc, 0, sizeof( testResVoidAlloc ) ); + + size_t maxItems = 1 << 18; // 512k objects + TestStartupParamsAndResults params; + params.startupParams.iterCount = 100000000; + params.startupParams.maxItemSize = 10; // 1k + params.startupParams.mat = MEM_ACCESS_TYPE::full; + params.startupParams.rndSeed = 41; + + size_t threadMin = 1; + size_t threadMax = 6; + size_t threadCount = threadMax; + if (argc==2) { + char* end; + long l = strtol(argv[1],&end,10); + if (l > 0) threadCount = l; + } + fprintf(stderr,"threads: %li\n", threadCount); +#ifdef BENCH + params.startupParams.threadCount=threadCount; + params.startupParams.maxItems = maxItems / params.startupParams.threadCount; + params.testRes = testResMyAlloc + params.startupParams.threadCount; + runTest( ¶ms ); +#else + for ( params.startupParams.threadCount=threadMin; params.startupParams.threadCount<=threadMax; ++(params.startupParams.threadCount) ) + { + params.startupParams.maxItems = maxItems / params.startupParams.threadCount; + params.testRes = testResMyAlloc + params.startupParams.threadCount; + runTest( ¶ms ); + + if ( params.startupParams.mat != MEM_ACCESS_TYPE::check ) + { + params.startupParams.maxItems = maxItems / params.startupParams.threadCount; + params.testRes = testResVoidAlloc + params.startupParams.threadCount; + runTest>( ¶ms ); + } + } +#endif + + if ( params.startupParams.mat == MEM_ACCESS_TYPE::check ) + { + printf( "Correctness test has been passed successfully\n" ); + return 0; + } + +#ifndef BENCH + printf( "Test summary:\n" ); + for ( size_t threadCount=threadMin; threadCount<=threadMax; ++threadCount ) + { + TestRes& trVoid = testResVoidAlloc[threadCount]; + TestRes& trMy = testResMyAlloc[threadCount]; + printf( "%zd,%zd,%zd,%zd\n", threadCount, trMy.duration, trVoid.duration, trMy.duration - trVoid.duration ); + printf( "Per-thread stats:\n" ); + for ( size_t i=0;i nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ------------------------------------------------------------------------------- + * + * Memory allocator tester + * + * v.1.00 Jun-22-2018 Initial release + * + * -------------------------------------------------------------------------------*/ +#ifndef ALLOCATOR_TESTER_H +#define ALLOCATOR_TESTER_H + +#include +#define NOMINMAX + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef __GNUC__ +#include +#else +#endif + +#include "test_common.h" +#include "void_allocator.h" // used as an estimation of the cost of test itself + + +class PRNG +{ + uint64_t seedVal; +public: + PRNG() { seedVal = 0; } + PRNG( size_t seed_ ) { seedVal = seed_; } + void seed( size_t seed_ ) { seedVal = seed_; } + + /*FORCE_INLINE uint32_t rng32( uint32_t x ) + { + // Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + return x; + }*/ +/* FORCE_INLINE uint32_t rng32() + { + unsigned long long x = (seedVal += 7319936632422683443ULL); + x ^= x >> 32; + x *= c; + x ^= x >> 32; + x *= c; + x ^= x >> 32; + return uint32_t(x); + }*/ + FORCE_INLINE uint32_t rng32() + { + // based on implementation of xorshift by Arvid Gerstmann + // see, for instance, https://arvid.io/2018/07/02/better-cxx-prng/ + uint64_t ret = seedVal * 0xd989bcacc137dcd5ull; + seedVal ^= seedVal >> 11; + seedVal ^= seedVal << 31; + seedVal ^= seedVal >> 18; + return uint32_t(ret >> 32ull); + } + + FORCE_INLINE uint64_t rng64() + { + uint64_t ret = rng32(); + ret <<= 32; + return ret + rng32(); + } +}; + +FORCE_INLINE size_t calcSizeWithStatsAdjustment( uint64_t randNum, size_t maxSizeExp ) +{ + assert( maxSizeExp >= 3 ); + maxSizeExp -= 3; + uint32_t statClassBase = (randNum & (( 1 << maxSizeExp ) - 1)) + 1; // adding 1 to avoid dealing with 0 + randNum >>= maxSizeExp; + unsigned long idx; +#if _MSC_VER + uint8_t r = _BitScanForward(&idx, statClassBase); + assert( r ); +#elif __GNUC__ + idx = __builtin_ctzll( statClassBase ); +#else + static_assert(false, "Unknown compiler"); +#endif +// assert( idx <= maxSizeExp - 3 ); + assert( idx <= maxSizeExp ); + idx += 2; + size_t szMask = ( 1 << idx ) - 1; + return (randNum & szMask) + 1 + (((size_t)1)< (((size_t)1)<<(j-1) ) ) + bins[j] += 1; + } + printf( "<=3: %zd\n", bins[0] + bins[1] + bins[2] + bins[3] ); + total = 0; + for ( size_t j=0; j<=exp; ++j ) + { + total += bins[j]; + printf( "%zd: %zd\n", j, bins[j] ); + } + assert( total == testCnt ); +} + + +constexpr double Pareto_80_20_6[7] = { + 0.262144000000, + 0.393216000000, + 0.245760000000, + 0.081920000000, + 0.015360000000, + 0.001536000000, + 0.000064000000}; + +struct Pareto_80_20_6_Data +{ + uint32_t probabilityRanges[6]; + uint32_t offsets[8]; +}; + +FORCE_INLINE +void Pareto_80_20_6_Init( Pareto_80_20_6_Data& data, uint32_t itemCount ) +{ + data.probabilityRanges[0] = (uint32_t)(UINT32_MAX * Pareto_80_20_6[0]); + data.probabilityRanges[5] = (uint32_t)(UINT32_MAX * (1. - Pareto_80_20_6[6])); + for ( size_t i=1; i<5; ++i ) + data.probabilityRanges[i] = data.probabilityRanges[i-1] + (uint32_t)(UINT32_MAX * Pareto_80_20_6[i]); + data.offsets[0] = 0; + data.offsets[7] = itemCount; + for ( size_t i=0; i<6; ++i ) + data.offsets[i+1] = data.offsets[i] + (uint32_t)(itemCount * Pareto_80_20_6[6-i]); +} + +FORCE_INLINE +size_t Pareto_80_20_6_Rand( const Pareto_80_20_6_Data& data, uint32_t rnum1, uint32_t rnum2 ) +{ + size_t idx = 6; + if ( rnum1 < data.probabilityRanges[0] ) + idx = 0; + else if ( rnum1 < data.probabilityRanges[1] ) + idx = 1; + else if ( rnum1 < data.probabilityRanges[2] ) + idx = 2; + else if ( rnum1 < data.probabilityRanges[3] ) + idx = 3; + else if ( rnum1 < data.probabilityRanges[4] ) + idx = 4; + else if ( rnum1 < data.probabilityRanges[5] ) + idx = 5; + uint32_t rangeSize = data.offsets[ idx + 1 ] - data.offsets[ idx ]; + uint32_t offsetInRange = rnum2 % rangeSize; + return data.offsets[ idx ] + offsetInRange; +} + +void fillSegmentWithRandomData( uint8_t* ptr, size_t sz, size_t reincarnation ) +{ + PRNG rng( ((uintptr_t)ptr) ^ ((uintptr_t)sz << 32) ^ reincarnation ); + for ( size_t i=0; i<(sz>>2); ++i ) + (reinterpret_cast(ptr))[i] = rng.rng32(); + ptr += (sz>>2)<<2; + if ( sz & 3 ) + { + uint32_t last = rng.rng32(); + for ( size_t i=0; i<(sz&3); ++i ) + { + (ptr)[i] = (uint8_t)last; + last >>= 8; + } + } +} +void checkSegment( uint8_t* ptr, size_t sz, size_t reincarnation ) +{ + PRNG rng( ((uintptr_t)ptr) ^ ((uintptr_t)sz << 32) ^ reincarnation ); + for ( size_t i=0; i<(sz>>2); ++i ) + if ( (reinterpret_cast(ptr))[i] != rng.rng32() ) + { + printf( "memcheck failed for ptr=%zd, size=%zd, reincarnation=%zd, from %zd\n", (size_t)(ptr), sz, reincarnation, i*4 ); + throw std::bad_alloc(); + } + ptr += (sz>>2)<<2; + if ( sz & 3 ) + { + uint32_t last = rng.rng32(); + for ( size_t i=0; i<(sz&3); ++i ) + { + if( (ptr)[i] != (uint8_t)last ) + { + printf( "memcheck failed for ptr=%zd, size=%zd, reincarnation=%zd, from %zd\n", (size_t)(ptr), sz, reincarnation, ((sz>>2)<<2) + i ); + throw std::bad_alloc(); + } + last >>= 8; + } + } +} + +template< class AllocatorUnderTest, MEM_ACCESS_TYPE mat> +void randomPos_RandomSize( AllocatorUnderTest& allocatorUnderTest, size_t iterCount, size_t maxItems, size_t maxItemSizeExp, size_t threadID, size_t rnd_seed ) +{ + if( maxItemSizeExp >= 32 ) + { + printf( "allocation sizes greater than 2^31 are not yet supported; revise implementation, if desired\n" ); + throw std::bad_exception(); + } + + static constexpr const char* memAccessTypeStr = mat == MEM_ACCESS_TYPE::none ? "none" : ( mat == MEM_ACCESS_TYPE::single ? "single" : ( mat == MEM_ACCESS_TYPE::full ? "full" : ( mat == MEM_ACCESS_TYPE::check ? "check" : "unknown" ) ) ); + printf( " running thread %zd with \'%s\' and maxItemSizeExp = %zd, maxItems = %zd, iterCount = %zd, allocated memory access mode: %s, [rnd_seed = %llu] ...\n", threadID, allocatorUnderTest.name(), maxItemSizeExp, maxItems, iterCount, memAccessTypeStr, rnd_seed ); + constexpr bool doMemAccess = mat != MEM_ACCESS_TYPE::none; + allocatorUnderTest.init(); + allocatorUnderTest.getTestRes()->threadID = threadID; // just as received + allocatorUnderTest.getTestRes()->rdtscBegin = get_timestamp(); + + size_t start = GetMillisecondCount(); + + size_t dummyCtr = 0; + size_t rssMax = 0; + size_t rss; + size_t allocatedSz = 0; + size_t allocatedSzMax = 0; + + uint32_t reincarnation = 0; + + Pareto_80_20_6_Data paretoData; + assert( maxItems <= UINT32_MAX ); + Pareto_80_20_6_Init( paretoData, (uint32_t)maxItems ); + + struct TestBin + { + uint8_t* ptr; + uint32_t sz; + uint32_t reincarnation; + }; + + TestBin* baseBuff = nullptr; + //if constexpr ( !allocatorUnderTest.isFake() ) + baseBuff = reinterpret_cast( allocatorUnderTest.allocate( maxItems * sizeof(TestBin) ) ); + //else + // baseBuff = reinterpret_cast( allocatorUnderTest.allocateSlots( maxItems * sizeof(TestBin) ) ); + assert( baseBuff ); + allocatedSz += maxItems * sizeof(TestBin); + memset( baseBuff, 0, maxItems * sizeof( TestBin ) ); + + PRNG rng(rnd_seed); + + // setup (saturation) + for ( size_t i=0;i> j) & 1 ) + { + size_t randNumSz = rng.rng64(); + size_t sz = calcSizeWithStatsAdjustment( randNumSz, maxItemSizeExp ); + baseBuff[i*32+j].sz = (uint32_t)sz; + baseBuff[i*32+j].ptr = reinterpret_cast( allocatorUnderTest.allocate( sz ) ); + if constexpr ( doMemAccess ) + { + if constexpr ( mat == MEM_ACCESS_TYPE::full ) + memset( baseBuff[i*32+j].ptr, (uint8_t)sz, sz ); + else + { + if constexpr ( mat == MEM_ACCESS_TYPE::single ) + baseBuff[i*32+j].ptr[sz/2] = (uint8_t)sz; + else + { + static_assert( mat == MEM_ACCESS_TYPE::check, "" ); + baseBuff[i*32+j].reincarnation = reincarnation; + fillSegmentWithRandomData( baseBuff[i*32+j].ptr, sz, reincarnation++ ); + } + } + } + allocatedSz += sz; + } + } + allocatorUnderTest.doWhateverAfterSetupPhase(); + allocatorUnderTest.getTestRes()->rdtscSetup = get_timestamp(); + allocatorUnderTest.getTestRes()->allocatedAfterSetupSz = allocatedSz; + + rss = getRss(); + if ( rssMax < rss ) rssMax = rss; + + // main loop + for ( size_t k=0 ; k<32; ++k ) + { + for ( size_t j=0;j>5; ++j ) + { + uint32_t rnum1 = rng.rng32(); + uint32_t rnum2 = rng.rng32(); + size_t idx = Pareto_80_20_6_Rand( paretoData, rnum1, rnum2 ); + if ( baseBuff[idx].ptr ) + { + if constexpr ( doMemAccess ) + { + if constexpr ( mat == MEM_ACCESS_TYPE::full ) + { + size_t i=0; + for ( ; i( baseBuff[idx].ptr) )[i]; + uint8_t* tail = baseBuff[idx].ptr + i * sizeof(size_t ); + for ( i=0; i( allocatorUnderTest.allocate( sz ) ); + if constexpr ( doMemAccess ) + { + if constexpr ( mat == MEM_ACCESS_TYPE::full ) + memset( baseBuff[idx].ptr, (uint8_t)sz, sz ); + else + { + if constexpr ( mat == MEM_ACCESS_TYPE::single ) + baseBuff[idx].ptr[sz/2] = (uint8_t)sz; + else + { + static_assert( mat == MEM_ACCESS_TYPE::check, "" ); + baseBuff[idx].reincarnation = reincarnation; + fillSegmentWithRandomData( baseBuff[idx].ptr, sz, reincarnation++ ); + } + } + } +#ifdef COLLECT_USER_MAX_ALLOCATED + allocatedSz += sz; + if ( allocatedSzMax < allocatedSz ) + allocatedSzMax = allocatedSz; +#endif + } + } + rss = getRss(); + if ( rssMax < rss ) rssMax = rss; + } + allocatorUnderTest.doWhateverAfterMainLoopPhase(); + allocatorUnderTest.getTestRes()->rdtscMainLoop = get_timestamp(); + allocatorUnderTest.getTestRes()->allocatedMax = allocatedSzMax; + + // exit + for ( size_t idx=0; idx( baseBuff[idx].ptr) )[i]; + uint8_t* tail = baseBuff[idx].ptr + i * sizeof(size_t ); + for ( i=0; irdtscExit = get_timestamp(); + allocatorUnderTest.getTestRes()->innerDur = GetMillisecondCount() - start; + allocatorUnderTest.doWhateverAfterCleanupPhase(); + + rss = getRss(); + if ( rssMax < rss ) rssMax = rss; + allocatorUnderTest.getTestRes()->rssMax = rssMax; + + printf( "about to exit thread %zd (%zd operations performed) [ctr = %zd]...\n", threadID, iterCount, dummyCtr ); +}; + +#endif // ALLOCATOR_TESTER_H diff --git a/benchmarks/benchmarks/alloc-test/new_delete_allocator.h b/benchmarks/benchmarks/alloc-test/new_delete_allocator.h new file mode 100644 index 0000000..1fb8eea --- /dev/null +++ b/benchmarks/benchmarks/alloc-test/new_delete_allocator.h @@ -0,0 +1,67 @@ +/* ------------------------------------------------------------------------------- + * Copyright (c) 2018, OLogN Technologies AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ------------------------------------------------------------------------------- + * + * Memory allocator tester -- new-delete allocator + * + * v.1.00 Jun-22-2018 Initial release + * + * -------------------------------------------------------------------------------*/ + + +#ifndef NEW_DELETE_ALLOCATOR_H +#define NEW_DELETE_ALLOCATOR_H + +#include "test_common.h" + + +class NewDeleteAllocatorForTest +{ + ThreadTestRes* testRes; + +public: + NewDeleteAllocatorForTest( ThreadTestRes* testRes_ ) { testRes = testRes_; } + static constexpr bool isFake() { return false; } + + static constexpr const char* name() { return "new-delete allocator"; } + + void init() {} + void* allocate( size_t sz ) { return new uint8_t[ sz ]; } + void deallocate( void* ptr ) { delete [] reinterpret_cast(ptr); } + void deinit() {} + + // next calls are to get additional stats of the allocator, etc, if desired + void doWhateverAfterSetupPhase() {} + void doWhateverAfterMainLoopPhase() {} + void doWhateverAfterCleanupPhase() {} + + ThreadTestRes* getTestRes() { return testRes; } +}; + + + + +#endif // NEW_DELETE_ALLOCATOR_H diff --git a/benchmarks/benchmarks/alloc-test/selector.h b/benchmarks/benchmarks/alloc-test/selector.h new file mode 100644 index 0000000..c79b40d --- /dev/null +++ b/benchmarks/benchmarks/alloc-test/selector.h @@ -0,0 +1,46 @@ +/* ------------------------------------------------------------------------------- + * Copyright (c) 2018, OLogN Technologies AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ------------------------------------------------------------------------------- + * + * Memory allocator tester -- selector + * + * v.1.00 Jun-22-2018 Initial release + * + * -------------------------------------------------------------------------------*/ + + +#ifndef SELECTOR_H +#define SELECTOR_H + +// TODO: +// (1) #include "my_allocator.h" +// (2) define MyAllocatorT properly +// (3) make sure other inclusions and/or definitions are removed or commented out :) + +#include "new_delete_allocator.h" +typedef NewDeleteAllocatorForTest MyAllocatorT; + +#endif // SELECTOR_H diff --git a/benchmarks/benchmarks/alloc-test/test_common.cpp b/benchmarks/benchmarks/alloc-test/test_common.cpp new file mode 100644 index 0000000..5e7140f --- /dev/null +++ b/benchmarks/benchmarks/alloc-test/test_common.cpp @@ -0,0 +1,140 @@ +/* ------------------------------------------------------------------------------- + * Copyright (c) 2018, OLogN Technologies AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ------------------------------------------------------------------------------- + * + * Memory allocator tester -- common + * + * v.1.00 Jun-22-2018 Initial release + * + * -------------------------------------------------------------------------------*/ + + +#include "test_common.h" + +#include +#include + +#ifdef _MSC_VER +#include +#else +#include +#endif + + +int64_t GetMicrosecondCount() +{ + int64_t now = 0; +#ifdef _MSC_VER + static int64_t frec = 0; + if (frec == 0) + { + LARGE_INTEGER val; + BOOL ok = QueryPerformanceFrequency(&val); + assert(ok); + frec = val.QuadPart; + } + LARGE_INTEGER val; + BOOL ok = QueryPerformanceCounter(&val); + assert(ok); + now = (val.QuadPart * 1000000) / frec; +#endif + return now; +} + + + +NOINLINE +size_t GetMillisecondCount() +{ + size_t now; +#ifdef _MSC_VER + static uint64_t frec = 0; + if (frec == 0) + { + LARGE_INTEGER val; + BOOL ok = QueryPerformanceFrequency(&val); + assert(ok); + frec = val.QuadPart / 1000; + } + LARGE_INTEGER val; + BOOL ok = QueryPerformanceCounter(&val); + assert(ok); + now = val.QuadPart / frec; + +#else +#if 1 + struct timespec ts; + timespec_get(&ts, TIME_UTC);//clock get time monotonic + now = (uint64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; // mks +#else + struct timeval now_; + gettimeofday(&now_, NULL); + now = now_.tv_sec; + now *= 1000; + now += now_.tv_usec / 1000000; +#endif +#endif + return now; +} + +#ifdef _MSC_VER +#include +size_t getRss() +{ + HANDLE hProcess; + PROCESS_MEMORY_COUNTERS pmc; + hProcess = GetCurrentProcess(); + BOOL ok = GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc)); + CloseHandle( hProcess ); + if ( ok ) + return pmc.PagefileUsage >> 12; // note: we may also be interested in 'PeakPagefileUsage' + else + return 0; +} +#elif defined(__APPLE__) +#include +size_t getRss() { + struct rusage rusage; + getrusage(RUSAGE_SELF, &rusage); + return rusage.ru_maxrss; +} +#else +size_t getRss() +{ + // see http://man7.org/linux/man-pages/man5/proc.5.html for details + FILE* fstats = fopen( "/proc/self/statm", "rb" ); + constexpr size_t buffsz = 0x1000; + char buff[buffsz]; + buff[buffsz-1] = 0; + fread( buff, 1, buffsz-1, fstats); + fclose( fstats); + const char* pos = buff; + while ( *pos && *pos == ' ' ) ++pos; + while ( *pos && *pos != ' ' ) ++pos; + return atol( pos ); +} +#endif + diff --git a/benchmarks/benchmarks/alloc-test/test_common.h b/benchmarks/benchmarks/alloc-test/test_common.h new file mode 100644 index 0000000..c65aba8 --- /dev/null +++ b/benchmarks/benchmarks/alloc-test/test_common.h @@ -0,0 +1,151 @@ +/* ------------------------------------------------------------------------------- + * Copyright (c) 2018, OLogN Technologies AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ------------------------------------------------------------------------------- + * + * Memory allocator tester -- common + * + * v.1.00 Jun-22-2018 Initial release + * + * -------------------------------------------------------------------------------*/ + + +#ifndef ALLOCATOR_TEST_COMMON_H +#define ALLOCATOR_TEST_COMMON_H + +#include +#include +#include +#include +#include +#include + +#if _MSC_VER +#include +#define ALIGN(n) __declspec(align(n)) +#define NOINLINE __declspec(noinline) +#define FORCE_INLINE __forceinline +#elif __GNUC__ +#if defined(__APPLE__) +#include +//#if defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC) +static inline uint64_t get_timestamp(void) { + struct timespec t; + #ifdef CLOCK_MONOTONIC + clock_gettime(CLOCK_MONOTONIC, &t); + #else + clock_gettime(CLOCK_REALTIME, &t); + #endif + return ((uint64_t)t.tv_sec * 1000) + ((uint64_t)t.tv_nsec / 1000000); +} +#else +#include +static inline uint64_t get_timestamp(void) { + return __rdtsc(); +} +#endif +#define ALIGN(n) __attribute__ ((aligned(n))) +#define NOINLINE __attribute__ ((noinline)) +#define FORCE_INLINE inline __attribute__((always_inline)) +#else +#define FORCE_INLINE inline +#define NOINLINE +//#define ALIGN(n) +#warning ALIGN, FORCE_INLINE and NOINLINE may not be properly defined +#endif + +int64_t GetMicrosecondCount(); +size_t GetMillisecondCount(); +size_t getRss(); + +constexpr size_t max_threads = 32; + +enum MEM_ACCESS_TYPE { none, single, full, check }; + +#define COLLECT_USER_MAX_ALLOCATED + +struct ThreadTestRes +{ + size_t threadID; + + size_t innerDur; + + uint64_t rdtscBegin; + uint64_t rdtscSetup; + uint64_t rdtscMainLoop; + uint64_t rdtscExit; + + size_t rssMax; + size_t allocatedAfterSetupSz; +#ifdef COLLECT_USER_MAX_ALLOCATED + size_t allocatedMax; +#endif +}; + +inline +void printThreadStats( const char* prefix, ThreadTestRes& res ) +{ + uint64_t rdtscTotal = res.rdtscExit - res.rdtscBegin; + printf( "%s%zd: %zdms; %zd (%.2f | %.2f | %.2f);\n", prefix, res.threadID, res.innerDur, rdtscTotal, (res.rdtscSetup - res.rdtscBegin) * 100. / rdtscTotal, (res.rdtscMainLoop - res.rdtscSetup) * 100. / rdtscTotal, (res.rdtscExit - res.rdtscMainLoop) * 100. / rdtscTotal ); +} + +struct TestRes +{ + size_t duration; + size_t cumulativeDuration; + size_t rssMax; + size_t allocatedAfterSetupSz; + size_t rssAfterExitingAllThreads; +#ifdef COLLECT_USER_MAX_ALLOCATED + size_t allocatedMax; +#endif + ThreadTestRes threadRes[max_threads]; +}; + +struct TestStartupParams +{ + size_t threadCount; + size_t maxItems; + size_t maxItemSize; + size_t iterCount; + MEM_ACCESS_TYPE mat; + size_t rndSeed; +}; + +struct TestStartupParamsAndResults +{ + TestStartupParams startupParams; + TestRes* testRes; +}; + +struct ThreadStartupParamsAndResults +{ + TestStartupParams startupParams; + size_t threadID; + ThreadTestRes* threadRes; +}; + + +#endif // ALLOCATOR_TEST_COMMON_H \ No newline at end of file diff --git a/benchmarks/benchmarks/alloc-test/void_allocator.h b/benchmarks/benchmarks/alloc-test/void_allocator.h new file mode 100644 index 0000000..9913386 --- /dev/null +++ b/benchmarks/benchmarks/alloc-test/void_allocator.h @@ -0,0 +1,77 @@ +/* ------------------------------------------------------------------------------- + * Copyright (c) 2018, OLogN Technologies AG + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ------------------------------------------------------------------------------- + * + * Memory allocator tester -- void allocator (used for estimating cost of test itself) + * + * v.1.00 Jun-22-2018 Initial release + * + * -------------------------------------------------------------------------------*/ + + +#ifndef VOID_ALLOCATOR_H +#define VOID_ALLOCATOR_H + +#include "test_common.h" + +template +class VoidAllocatorForTest +{ + ThreadTestRes* testRes; + ThreadTestRes discardedTestRes; + ActualAllocator alloc; + uint8_t* fakeBuffer = nullptr; + static constexpr size_t fakeBufferSize = 0x1000000; + +public: + VoidAllocatorForTest( ThreadTestRes* testRes_ ) : alloc( &discardedTestRes ) { testRes = testRes_; } + static constexpr bool isFake() { return true; } // thus indicating that certain checks over allocated memory should be ommited + + static constexpr const char* name() { return "void allocator"; } + + void init() + { + alloc.init(); + fakeBuffer = reinterpret_cast( alloc.allocate( fakeBufferSize ) ); + } + void* allocateSlots( size_t sz ) { static_assert( isFake()); assert( sz <= fakeBufferSize ); return alloc.allocate( sz ); } + void* allocate( size_t sz ) { assert( sz <= fakeBufferSize ); return fakeBuffer; } + void deallocate( void* ptr ) {} + void deallocateSlots( void* ptr ) {alloc.deallocate( ptr );} + void deinit() { if ( fakeBuffer ) alloc.deallocate( fakeBuffer ); fakeBuffer = nullptr; } + + // next calls are to get additional stats of the allocator, etc, if desired + void doWhateverAfterSetupPhase() {} + void doWhateverAfterMainLoopPhase() {} + void doWhateverAfterCleanupPhase() {} + + ThreadTestRes* getTestRes() { return testRes; } +}; + + + + +#endif // VOID_ALLOCATOR_H \ No newline at end of file diff --git a/benchmarks/benchmarks/barnes/README.barnes b/benchmarks/benchmarks/barnes/README.barnes new file mode 100644 index 0000000..940b477 --- /dev/null +++ b/benchmarks/benchmarks/barnes/README.barnes @@ -0,0 +1,52 @@ +GENERAL INFORMATION: + +The BARNES application implements the Barnes-Hut method to simulate the +interaction of a system of bodies (N-body problem). A general description +of the Barnes-Hut method can be found in: + +Singh, J. P. Parallel Hierarchical N-body Methods and Their Implications + for Multiprocessors. PhD Thesis, Stanford University, February 1993. + +The SPLASH-2 implementation allows for multiple particles to be stored in +each leaf cell of the space partition. A description of this feature +can be found in: + +Holt, C. and Singh, J. P. Hierarchical N-Body Methods on Shared Address + Space Multiprocessors. SIAM Conference on Parallel Processing + for Scientific Computing, Feb 1995, to appear. + +RUNNING THE PROGRAM: + +For a default run, use "BARNES < input". + +To see how to run the program, please see the comment at the top of the +file code.C, or run the application with the "-h" command line option. +The input parameters should be placed in a file and redirected to standard +input. Of the twelve input parameters, the ones which would normally be +varied are the number of particles and the number of processors. If other +parameters are changed, these changes should be reported in any results +that are presented. + +The only compile time option, -DQUADPOLE, controls the use of quadpole +interactions during the force computation. For the input parameters +provided, the -DQUADPOLE option should not be defined. The constant +MAX_BODIES_PER_LEAF defines the maximum number of particles per leaf +cell in the tree. This constant also affects the parameter "fleaves" in +the input file, which controls how many leaf cells space is allocated for. +The higher the value of MAX_BODIES_PER_LEAF, the lower fleaves should be. +Both these parameters should be kept at their default values for base +SPLASH-2 runs. If changes are made, they should be reported in any results +that are presented. + +BASE PROBLEM SIZE: + +The base problem size for an upto-64 processor machine is 16384 particles. +For this many particles, you can use the input file provided (and change +only the number of processors). + +DATA DISTRIBUTION: + +Our "POSSIBLE ENHANCEMENT" comments in the source code tell where one +might want to distribute data and how. Data distribution, however, does +not make much difference to performance on the Stanford DASH +multiprocessor. diff --git a/benchmarks/benchmarks/barnes/README.md b/benchmarks/benchmarks/barnes/README.md new file mode 100644 index 0000000..4209780 --- /dev/null +++ b/benchmarks/benchmarks/barnes/README.md @@ -0,0 +1,13 @@ +Copyright (c) 1994 Stanford University + +``` +All rights reserved. + +Permission is given to use, copy, and modify this software for any +non-commercial purpose as long as this copyright notice is not +removed. All other uses, including redistribution in whole or in +part, are forbidden without prior written permission. + +This software is provided with absolutely no warranty and no +support. +``` diff --git a/benchmarks/benchmarks/barnes/code.c b/benchmarks/benchmarks/barnes/code.c new file mode 100644 index 0000000..bb7142e --- /dev/null +++ b/benchmarks/benchmarks/barnes/code.c @@ -0,0 +1,829 @@ +#line 95 "./null_macros/c.m4.null" + +#line 1 "code.C" +/*************************************************************************/ +/* */ +/* Copyright (c) 1994 Stanford University */ +/* */ +/* All rights reserved. */ +/* */ +/* Permission is given to use, copy, and modify this software for any */ +/* non-commercial purpose as long as this copyright notice is not */ +/* removed. All other uses, including redistribution in whole or in */ +/* part, are forbidden without prior written permission. */ +/* */ +/* This software is provided with absolutely no warranty and no */ +/* support. */ +/* */ +/*************************************************************************/ +/* +Usage: BARNES < inputfile + +Command line options: + + -h : Print out input file description + + Input parameters should be placed in a file and redirected through + standard input. There are a total of twelve parameters, and all of + them have default values. + + 1) infile (char*) : The name of an input file that contains particle + data. + + The format of the file is: + a) An int representing the number of particles in the distribution + b) An int representing the dimensionality of the problem (3-D) + c) A double representing the current time of the simulation + d) Doubles representing the masses of all the particles + e) A vector (length equal to the dimensionality) of doubles + representing the positions of all the particles + f) A vector (length equal to the dimensionality) of doubles + representing the velocities of all the particles + + Each of these numbers can be separated by any amount of whitespace. + 2) nbody (int) : If no input file is specified (the first line is + blank), this number specifies the number of particles to generate + under a plummer model. Default is 16384. + 3) seed (int) : The seed used by the random number generator. + Default is 123. + 4) outfile (char*) : The name of the file that snapshots will be + printed to. This feature has been disabled in the SPLASH release. + Default is NULL. + 5) dtime (double) : The integration time-step. + Default is 0.025. + 6) eps (double) : The usual potential softening + Default is 0.05. + 7) tol (double) : The cell subdivision tolerance. + Default is 1.0. + 8) fcells (double) : Number of cells created = fcells * number of + leaves. + Default is 2.0. + 9) fleaves (double) : Number of leaves created = fleaves * nbody. + Default is 0.5. + 10) tstop (double) : The time to stop integration. + Default is 0.075. + 11) dtout (double) : The data-output interval. + Default is 0.25. + 12) NPROC (int) : The number of processors. + Default is 1. +*/ + + + +#define global /* nada */ + +#include "code.h" +#include "defs.h" +#include +#include + +string defv[] = { /* DEFAULT PARAMETER VALUES */ + /* file names for input/output */ + "in=", /* snapshot of initial conditions */ + "out=", /* stream of output snapshots */ + + /* params, used if no input specified, to make a Plummer Model */ + "nbody=16384", /* number of particles to generate */ + "seed=123", /* random number generator seed */ + + /* params to control N-body integration */ + "dtime=0.025", /* integration time-step */ + "eps=0.05", /* usual potential softening */ + "tol=1.0", /* cell subdivision tolerence */ + "fcells=2.0", /* cell allocation parameter */ + "fleaves=0.5", /* leaf allocation parameter */ + + "tstop=0.075", /* time to stop integration */ + "dtout=0.25", /* data-output interval */ + + "NPROC=1", /* number of processors */ +}; + +void SlaveStart (); +void stepsystem (unsigned int ProcessId); +void ComputeForces (); +void Help(); +FILE *fopen(); + +main(argc, argv) +int argc; +string argv[]; +{ + unsigned ProcessId = 0; + int c; + printf("Run this as\n BARNES < input \n for default values\n"); + while ((c = getopt(argc, argv, "h")) != -1) { + switch(c) { + case 'h': + Help(); + exit(-1); + break; + default: + fprintf(stderr, "Only valid option is \"-h\".\n"); + exit(-1); + break; + } + } + ANLinit(); + initparam(argv, defv); + startrun(); + initoutput(); + tab_init(); + + Global->tracktime = 0; + Global->partitiontime = 0; + Global->treebuildtime = 0; + Global->forcecalctime = 0; + + /* Create the slave processes: number of processors less one, + since the master will do work as well */ + Global->current_id = 0; + for(ProcessId = 1; ProcessId < NPROC; ProcessId++) { + {fprintf(stderr, "No more processors -- this is a uniprocessor version!\n"); exit(-1);}; + } + + /* Make the master do slave work so we don't waste the processor */ + {long time(); (Global->computestart) = time(0);}; + printf("COMPUTESTART = %12u\n",Global->computestart); + SlaveStart(); + + {long time(); (Global->computeend) = time(0);}; + + {;}; + + printf("COMPUTEEND = %12u\n",Global->computeend); + printf("COMPUTETIME = %12u\n",Global->computeend - Global->computestart); + printf("TRACKTIME = %12u\n",Global->tracktime); + printf("PARTITIONTIME = %12u\t%5.2f\n",Global->partitiontime, + ((float)Global->partitiontime)/Global->tracktime); + printf("TREEBUILDTIME = %12u\t%5.2f\n",Global->treebuildtime, + ((float)Global->treebuildtime)/Global->tracktime); + printf("FORCECALCTIME = %12u\t%5.2f\n",Global->forcecalctime, + ((float)Global->forcecalctime)/Global->tracktime); + printf("RESTTIME = %12u\t%5.2f\n", + Global->tracktime - Global->partitiontime - + Global->treebuildtime - Global->forcecalctime, + ((float)(Global->tracktime-Global->partitiontime- + Global->treebuildtime-Global->forcecalctime))/ + Global->tracktime); + {exit(0);}; +} + +/* + * ANLINIT : initialize ANL macros + */ +ANLinit() +{ + {;}; + /* Allocate global, shared memory */ + + Global = (struct GlobalMemory *) malloc(sizeof(struct GlobalMemory));; + if (Global==NULL) error("No initialization for Global\n"); + + {;}; + {;}; + {;}; + {;}; + {;}; + {;}; + + {;}; + {;}; +} + +/* + * INIT_ROOT: Processor 0 reinitialize the global root at each time step + */ +init_root (ProcessId) + unsigned int ProcessId; +{ + int i; + + Global->G_root=Local[0].ctab; + Type(Global->G_root) = CELL; + Done(Global->G_root) = FALSE; + Level(Global->G_root) = IMAX >> 1; + for (i = 0; i < NSUB; i++) { + Subp(Global->G_root)[i] = NULL; + } + Local[0].mynumcell=1; +} + +int Log_base_2(number) +int number; +{ + int cumulative; + int out; + + cumulative = 1; + for (out = 0; out < 20; out++) { + if (cumulative == number) { + return(out); + } + else { + cumulative = cumulative * 2; + } + } + + fprintf(stderr,"Log_base_2: couldn't find log2 of %d\n", number); + exit(-1); +} + +/* + * TAB_INIT : allocate body and cell data space + */ + +tab_init() +{ + cellptr pc; + int i; + char *starting_address, *ending_address; + + /*allocate leaf/cell space */ + maxleaf = (int) ((double) fleaves * nbody); + maxcell = fcells * maxleaf; + for (i = 0; i < NPROC; ++i) { + Local[i].ctab = (cellptr) malloc((maxcell / NPROC) * sizeof(cell));; + Local[i].ltab = (leafptr) malloc((maxleaf / NPROC) * sizeof(leaf));; + } + + /*allocate space for personal lists of body pointers */ + maxmybody = (nbody+maxleaf*MAX_BODIES_PER_LEAF)/NPROC; + Local[0].mybodytab = (bodyptr*) malloc(NPROC*maxmybody*sizeof(bodyptr));; + /* space is allocated so that every */ + /* process can have a maximum of maxmybody pointers to bodies */ + /* then there is an array of bodies called bodytab which is */ + /* allocated in the distribution generation or when the distr. */ + /* file is read */ + maxmycell = maxcell / NPROC; + maxmyleaf = maxleaf / NPROC; + Local[0].mycelltab = (cellptr*) malloc(NPROC*maxmycell*sizeof(cellptr));; + Local[0].myleaftab = (leafptr*) malloc(NPROC*maxmyleaf*sizeof(leafptr));; + + CellLock = (struct CellLockType *) malloc(sizeof(struct CellLockType));; + {;}; +} + +/* + * SLAVESTART: main task for each processor + */ +void SlaveStart() +{ + unsigned int ProcessId; + + /* Get unique ProcessId */ + {;}; + ProcessId = Global->current_id++; + {;}; + +/* POSSIBLE ENHANCEMENT: Here is where one might pin processes to + processors to avoid migration */ + + /* initialize mybodytabs */ + Local[ProcessId].mybodytab = Local[0].mybodytab + (maxmybody * ProcessId); + /* note that every process has its own copy */ + /* of mybodytab, which was initialized to the */ + /* beginning of the whole array by proc. 0 */ + /* before create */ + Local[ProcessId].mycelltab = Local[0].mycelltab + (maxmycell * ProcessId); + Local[ProcessId].myleaftab = Local[0].myleaftab + (maxmyleaf * ProcessId); +/* POSSIBLE ENHANCEMENT: Here is where one might distribute the + data across physically distributed memories as desired. + + One way to do this is as follows: + + int i; + + if (ProcessId == 0) { + for (i=0;iBarstart,NPROC); + +*/ + + Local[ProcessId].tout = Local[0].tout; + Local[ProcessId].tnow = Local[0].tnow; + Local[ProcessId].nstep = Local[0].nstep; + + find_my_initial_bodies(bodytab, nbody, ProcessId); + + /* main loop */ + while (Local[ProcessId].tnow < tstop + 0.1 * dtime) { + stepsystem(ProcessId); + } +} + + +/* + * STARTRUN: startup hierarchical N-body code. + */ + +startrun() +{ + string getparam(); + int getiparam(); + bool getbparam(); + double getdparam(); + int seed; + infile = getparam("in"); + + if (*infile != NULL) { + inputdata(); + } + else { + nbody = getiparam("nbody"); + if (nbody < 1) { + error("startrun: absurd nbody\n"); + } + seed = getiparam("seed"); + } + outfile = getparam("out"); + dtime = getdparam("dtime"); + dthf = 0.5 * dtime; + eps = getdparam("eps"); + epssq = eps*eps; + tol = getdparam("tol"); + tolsq = tol*tol; + fcells = getdparam("fcells"); + fleaves = getdparam("fleaves"); + tstop = getdparam("tstop"); + dtout = getdparam("dtout"); + NPROC = getiparam("NPROC"); + Local[0].nstep = 0; + pranset(seed); + testdata(); + setbound(); + Local[0].tout = Local[0].tnow + dtout; +} + +/* + * TESTDATA: generate Plummer model initial conditions for test runs, + * scaled to units such that M = -4E = G = 1 (Henon, Hegge, etc). + * See Aarseth, SJ, Henon, M, & Wielen, R (1974) Astr & Ap, 37, 183. + */ + +#define MFRAC 0.999 /* mass cut off at MFRAC of total */ + +testdata() +{ + real rsc, vsc, sqrt(), xrand(), pow(), rsq, r, v, x, y; + vector cmr, cmv; + register bodyptr p; + int rejects = 0; + int k; + int halfnbody, i; + float offset; + register bodyptr cp; + double tmp; + + headline = "Hack code: Plummer model"; + Local[0].tnow = 0.0; + bodytab = (bodyptr) malloc(nbody * sizeof(body));; + if (bodytab == NULL) { + error("testdata: not enuf memory\n"); + } + rsc = 9 * PI / 16; + vsc = sqrt(1.0 / rsc); + + CLRV(cmr); + CLRV(cmv); + + halfnbody = nbody / 2; + if (nbody % 2 != 0) halfnbody++; + for (p = bodytab; p < bodytab+halfnbody; p++) { + Type(p) = BODY; + Mass(p) = 1.0 / nbody; + Cost(p) = 1; + + r = 1 / sqrt(pow(xrand(0.0, MFRAC), -2.0/3.0) - 1); + /* reject radii greater than 10 */ + while (r > 9.0) { + rejects++; + r = 1 / sqrt(pow(xrand(0.0, MFRAC), -2.0/3.0) - 1); + } + pickshell(Pos(p), rsc * r); + ADDV(cmr, cmr, Pos(p)); + do { + x = xrand(0.0, 1.0); + y = xrand(0.0, 0.1); + + } while (y > x*x * pow(1 - x*x, 3.5)); + + v = sqrt(2.0) * x / pow(1 + r*r, 0.25); + pickshell(Vel(p), vsc * v); + ADDV(cmv, cmv, Vel(p)); + } + + offset = 4.0; + + for (p = bodytab + halfnbody; p < bodytab+nbody; p++) { + Type(p) = BODY; + Mass(p) = 1.0 / nbody; + Cost(p) = 1; + + cp = p - halfnbody; + for (i = 0; i < NDIM; i++){ + Pos(p)[i] = Pos(cp)[i] + offset; + ADDV(cmr, cmr, Pos(p)); + Vel(p)[i] = Vel(cp)[i]; + ADDV(cmv, cmv, Vel(p)); + } + } + + DIVVS(cmr, cmr, (real) nbody); + DIVVS(cmv, cmv, (real) nbody); + + for (p = bodytab; p < bodytab+nbody; p++) { + SUBV(Pos(p), Pos(p), cmr); + SUBV(Vel(p), Vel(p), cmv); + } +} + +/* + * PICKSHELL: pick a random point on a sphere of specified radius. + */ + +pickshell(vec, rad) + real vec[]; /* coordinate vector chosen */ + real rad; /* radius of chosen point */ +{ + register int k; + double rsq, xrand(), sqrt(), rsc; + + do { + for (k = 0; k < NDIM; k++) { + vec[k] = xrand(-1.0, 1.0); + } + DOTVP(rsq, vec, vec); + } while (rsq > 1.0); + + rsc = rad / sqrt(rsq); + MULVS(vec, vec, rsc); +} + + + +int intpow(i,j) + int i,j; +{ + int k; + int temp = 1; + + for (k = 0; k < j; k++) + temp = temp*i; + return temp; +} + + +/* + * STEPSYSTEM: advance N-body system one time-step. + */ + +void +stepsystem (ProcessId) + unsigned int ProcessId; +{ + int i; + real Cavg; + bodyptr p,*pp; + vector acc1, dacc, dvel, vel1, dpos; + int intpow(); + unsigned int time; + unsigned int trackstart, trackend; + unsigned int partitionstart, partitionend; + unsigned int treebuildstart, treebuildend; + unsigned int forcecalcstart, forcecalcend; + + if (Local[ProcessId].nstep == 2) { +/* POSSIBLE ENHANCEMENT: Here is where one might reset the + statistics that one is measuring about the parallel execution */ + } + + if ((ProcessId == 0) && (Local[ProcessId].nstep >= 2)) { + {long time(); (trackstart) = time(0);}; + } + + if (ProcessId == 0) { + init_root(ProcessId); + } + else { + Local[ProcessId].mynumcell = 0; + Local[ProcessId].mynumleaf = 0; + } + + + /* start at same time */ + {;}; + + if ((ProcessId == 0) && (Local[ProcessId].nstep >= 2)) { + {long time(); (treebuildstart) = time(0);}; + } + + /* load bodies into tree */ + maketree(ProcessId); + + if ((ProcessId == 0) && (Local[ProcessId].nstep >= 2)) { + {long time(); (treebuildend) = time(0);}; + Global->treebuildtime += treebuildend - treebuildstart; + } + + Housekeep(ProcessId); + + Cavg = (real) Cost(Global->G_root) / (real)NPROC ; + Local[ProcessId].workMin = (int) (Cavg * ProcessId); + Local[ProcessId].workMax = (int) (Cavg * (ProcessId + 1) + + (ProcessId == (NPROC - 1))); + + if ((ProcessId == 0) && (Local[ProcessId].nstep >= 2)) { + {long time(); (partitionstart) = time(0);}; + } + + Local[ProcessId].mynbody = 0; + find_my_bodies(Global->G_root, 0, BRC_FUC, ProcessId ); + +/* B*RRIER(Global->Barcom,NPROC); */ + if ((ProcessId == 0) && (Local[ProcessId].nstep >= 2)) { + {long time(); (partitionend) = time(0);}; + Global->partitiontime += partitionend - partitionstart; + } + + if ((ProcessId == 0) && (Local[ProcessId].nstep >= 2)) { + {long time(); (forcecalcstart) = time(0);}; + } + + ComputeForces(ProcessId); + + if ((ProcessId == 0) && (Local[ProcessId].nstep >= 2)) { + {long time(); (forcecalcend) = time(0);}; + Global->forcecalctime += forcecalcend - forcecalcstart; + } + + /* advance my bodies */ + for (pp = Local[ProcessId].mybodytab; + pp < Local[ProcessId].mybodytab+Local[ProcessId].mynbody; pp++) { + p = *pp; + MULVS(dvel, Acc(p), dthf); + ADDV(vel1, Vel(p), dvel); + MULVS(dpos, vel1, dtime); + ADDV(Pos(p), Pos(p), dpos); + ADDV(Vel(p), vel1, dvel); + + for (i = 0; i < NDIM; i++) { + if (Pos(p)[i]Local[ProcessId].max[i]) { + Local[ProcessId].max[i]=Pos(p)[i] ; + } + } + } + {;}; + for (i = 0; i < NDIM; i++) { + if (Global->min[i] > Local[ProcessId].min[i]) { + Global->min[i] = Local[ProcessId].min[i]; + } + if (Global->max[i] < Local[ProcessId].max[i]) { + Global->max[i] = Local[ProcessId].max[i]; + } + } + {;}; + + /* bar needed to make sure that every process has computed its min */ + /* and max coordinates, and has accumulated them into the global */ + /* min and max, before the new dimensions are computed */ + {;}; + + if ((ProcessId == 0) && (Local[ProcessId].nstep >= 2)) { + {long time(); (trackend) = time(0);}; + Global->tracktime += trackend - trackstart; + } + if (ProcessId==0) { + Global->rsize=0; + SUBV(Global->max,Global->max,Global->min); + for (i = 0; i < NDIM; i++) { + if (Global->rsize < Global->max[i]) { + Global->rsize = Global->max[i]; + } + } + ADDVS(Global->rmin,Global->min,-Global->rsize/100000.0); + Global->rsize = 1.00002*Global->rsize; + SETVS(Global->min,1E99); + SETVS(Global->max,-1E99); + } + Local[ProcessId].nstep++; + Local[ProcessId].tnow = Local[ProcessId].tnow + dtime; +} + + + +void +ComputeForces (ProcessId) + unsigned int ProcessId; +{ + bodyptr p,*pp; + vector acc1, dacc, dvel, vel1, dpos; + + for (pp = Local[ProcessId].mybodytab; + pp < Local[ProcessId].mybodytab+Local[ProcessId].mynbody;pp++) { + p = *pp; + SETV(acc1, Acc(p)); + Cost(p)=0; + hackgrav(p,ProcessId); + Local[ProcessId].myn2bcalc += Local[ProcessId].myn2bterm; + Local[ProcessId].mynbccalc += Local[ProcessId].mynbcterm; + if (!Local[ProcessId].skipself) { /* did we miss self-int? */ + Local[ProcessId].myselfint++; /* count another goofup */ + } + if (Local[ProcessId].nstep > 0) { + /* use change in accel to make 2nd order correction to vel */ + SUBV(dacc, Acc(p), acc1); + MULVS(dvel, dacc, dthf); + ADDV(Vel(p), Vel(p), dvel); + } + } +} + +/* + * FIND_MY_INITIAL_BODIES: puts into mybodytab the initial list of bodies + * assigned to the processor. + */ + +find_my_initial_bodies(btab, nbody, ProcessId) +bodyptr btab; +int nbody; +unsigned int ProcessId; +{ + int Myindex; + int intpow(); + int equalbodies; + int extra,offset,i; + + Local[ProcessId].mynbody = nbody / NPROC; + extra = nbody % NPROC; + if (ProcessId < extra) { + Local[ProcessId].mynbody++; + offset = Local[ProcessId].mynbody * ProcessId; + } + if (ProcessId >= extra) { + offset = (Local[ProcessId].mynbody+1) * extra + (ProcessId - extra) + * Local[ProcessId].mynbody; + } + for (i=0; i < Local[ProcessId].mynbody; i++) { + Local[ProcessId].mybodytab[i] = &(btab[offset+i]); + } + {;}; +} + + +find_my_bodies(mycell, work, direction, ProcessId) + nodeptr mycell; + int work; + int direction; + unsigned ProcessId; +{ + int i; + leafptr l; + nodeptr qptr; + + if (Type(mycell) == LEAF) { + l = (leafptr) mycell; + for (i = 0; i < l->num_bodies; i++) { + if (work >= Local[ProcessId].workMin - .1) { + if((Local[ProcessId].mynbody+2) > maxmybody) { + error("find_my_bodies: Processor %d needs more than %d bodies; increase fleaves\n",ProcessId, maxmybody); + } + Local[ProcessId].mybodytab[Local[ProcessId].mynbody++] = + Bodyp(l)[i]; + } + work += Cost(Bodyp(l)[i]); + if (work >= Local[ProcessId].workMax-.1) { + break; + } + } + } + else { + for(i = 0; (i < NSUB) && (work < (Local[ProcessId].workMax - .1)); i++){ + qptr = Subp(mycell)[Child_Sequence[direction][i]]; + if (qptr!=NULL) { + if ((work+Cost(qptr)) >= (Local[ProcessId].workMin -.1)) { + find_my_bodies(qptr,work, Direction_Sequence[direction][i], + ProcessId); + } + work += Cost(qptr); + } + } + } +} + +/* + * HOUSEKEEP: reinitialize the different variables (in particular global + * variables) between each time step. + */ + +Housekeep(ProcessId) +unsigned ProcessId; +{ + Local[ProcessId].myn2bcalc = Local[ProcessId].mynbccalc + = Local[ProcessId].myselfint = 0; + SETVS(Local[ProcessId].min,1E99); + SETVS(Local[ProcessId].max,-1E99); +} + +/* + * SETBOUND: Compute the initial size of the root of the tree; only done + * before first time step, and only processor 0 does it + */ +setbound() +{ + int i; + real side ; + bodyptr p; + + SETVS(Local[0].min,1E99); + SETVS(Local[0].max,-1E99); + side=0; + + for (p = bodytab; p < bodytab+nbody; p++) { + for (i=0; iLocal[0].max[i]) Local[0].max[i]=Pos(p)[i] ; + } + } + + SUBV(Local[0].max,Local[0].max,Local[0].min); + for (i=0; irmin,Local[0].min,-side/100000.0); + Global->rsize = 1.00002*side; + SETVS(Global->max,-1E99); + SETVS(Global->min,1E99); +} + +void +Help () +{ + printf("There are a total of twelve parameters, and all of them have default values.\n"); + printf("\n"); + printf("1) infile (char*) : The name of an input file that contains particle data. \n"); + printf(" The format of the file is:\n"); + printf("\ta) An int representing the number of particles in the distribution\n"); + printf("\tb) An int representing the dimensionality of the problem (3-D)\n"); + printf("\tc) A double representing the current time of the simulation\n"); + printf("\td) Doubles representing the masses of all the particles\n"); + printf("\te) A vector (length equal to the dimensionality) of doubles\n"); + printf("\t representing the positions of all the particles\n"); + printf("\tf) A vector (length equal to the dimensionality) of doubles\n"); + printf("\t representing the velocities of all the particles\n"); + printf("\n"); + printf(" Each of these numbers can be separated by any amount of whitespace.\n"); + printf("\n"); + printf("2) nbody (int) : If no input file is specified (the first line is blank), this\n"); + printf(" number specifies the number of particles to generate under a plummer model.\n"); + printf(" Default is 16384.\n"); + printf("\n"); + printf("3) seed (int) : The seed used by the random number generator.\n"); + printf(" Default is 123.\n"); + printf("\n"); + printf("4) outfile (char*) : The name of the file that snapshots will be printed to. \n"); + printf(" This feature has been disabled in the SPLASH release.\n"); + printf(" Default is NULL.\n"); + printf("\n"); + printf("5) dtime (double) : The integration time-step.\n"); + printf(" Default is 0.025.\n"); + printf("\n"); + printf("6) eps (double) : The usual potential softening\n"); + printf(" Default is 0.05.\n"); + printf("\n"); + printf("7) tol (double) : The cell subdivision tolerance.\n"); + printf(" Default is 1.0.\n"); + printf("\n"); + printf("8) fcells (double) : The total number of cells created is equal to \n"); + printf(" fcells * number of leaves.\n"); + printf(" Default is 2.0.\n"); + printf("\n"); + printf("9) fleaves (double) : The total number of leaves created is equal to \n"); + printf(" fleaves * nbody.\n"); + printf(" Default is 0.5.\n"); + printf("\n"); + printf("10) tstop (double) : The time to stop integration.\n"); + printf(" Default is 0.075.\n"); + printf("\n"); + printf("11) dtout (double) : The data-output interval.\n"); + printf(" Default is 0.25.\n"); + printf("\n"); + printf("12) NPROC (int) : The number of processors.\n"); + printf(" Default is 1.\n"); +} diff --git a/benchmarks/benchmarks/barnes/code.h b/benchmarks/benchmarks/barnes/code.h new file mode 100644 index 0000000..32a5e86 --- /dev/null +++ b/benchmarks/benchmarks/barnes/code.h @@ -0,0 +1,148 @@ +#line 95 "./null_macros/c.m4.null" + +#line 1 "code.H" +/*************************************************************************/ +/* */ +/* Copyright (c) 1994 Stanford University */ +/* */ +/* All rights reserved. */ +/* */ +/* Permission is given to use, copy, and modify this software for any */ +/* non-commercial purpose as long as this copyright notice is not */ +/* removed. All other uses, including redistribution in whole or in */ +/* part, are forbidden without prior written permission. */ +/* */ +/* This software is provided with absolutely no warranty and no */ +/* support. */ +/* */ +/*************************************************************************/ + +/* + * CODE.H: define various global things for CODE.C. + */ + +#ifndef _CODE_H_ +#define _CODE_H_ + +#include "defs.h" + +#define PAD_SIZE (PAGE_SIZE / (sizeof(int))) + +/* Defined by the input file */ +global string headline; /* message describing calculation */ +global string infile; /* file name for snapshot input */ +global string outfile; /* file name for snapshot output */ +global real dtime; /* timestep for leapfrog integrator */ +global real dtout; /* time between data outputs */ +global real tstop; /* time to stop calculation */ +global int nbody; /* number of bodies in system */ +global real fcells; /* ratio of cells/leaves allocated */ +global real fleaves; /* ratio of leaves/bodies allocated */ +global real tol; /* accuracy parameter: 0.0 => exact */ +global real tolsq; /* square of previous */ +global real eps; /* potential softening parameter */ +global real epssq; /* square of previous */ +global real dthf; /* half time step */ +global int NPROC; /* Number of Processors */ + +global int maxcell; /* max number of cells allocated */ +global int maxleaf; /* max number of leaves allocated */ +global int maxmybody; /* max no. of bodies allocated per processor */ +global int maxmycell; /* max num. of cells to be allocated */ +global int maxmyleaf; /* max num. of leaves to be allocated */ +global bodyptr bodytab; /* array size is exactly nbody bodies */ + +global struct CellLockType { + int (CL); /* locks on the cells*/ +} *CellLock; + +struct GlobalMemory { /* all this info is for the whole system */ + int n2bcalc; /* total number of body/cell interactions */ + int nbccalc; /* total number of body/body interactions */ + int selfint; /* number of self interactions */ + real mtot; /* total mass of N-body system */ + real etot[3]; /* binding, kinetic, potential energy */ + matrix keten; /* kinetic energy tensor */ + matrix peten; /* potential energy tensor */ + vector cmphase[2]; /* center of mass coordinates and velocity */ + vector amvec; /* angular momentum vector */ + cellptr G_root; /* root of the whole tree */ + vector rmin; /* lower-left corner of coordinate box */ + vector min; /* temporary lower-left corner of the box */ + vector max; /* temporary upper right corner of the box */ + real rsize; /* side-length of integer coordinate box */ + int (Barstart); /* barrier at the beginning of stepsystem */ + int (Bartree); /* barrier after loading the tree */ + int (Barcom); /* barrier after computing the c. of m. */ + int (Barload); + int (Baraccel); /* barrier after accel and before output */ + int (Barpos); /* barrier after computing the new pos */ + int (CountLock); /* Lock on the shared variables */ + int (NcellLock); /* Lock on the counter of array of cells for loadtree */ + int (NleafLock);/* Lock on the counter of array of leaves for loadtree */ + int (io_lock); + unsigned int createstart,createend,computestart,computeend; + unsigned int trackstart, trackend, tracktime; + unsigned int partitionstart, partitionend, partitiontime; + unsigned int treebuildstart, treebuildend, treebuildtime; + unsigned int forcecalcstart, forcecalcend, forcecalctime; + unsigned int current_id; + volatile int k; /*for memory allocation in code.C */ +}; +global struct GlobalMemory *Global; + +/* This structure is needed because under the sproc model there is no + * per processor private address space. + */ +struct local_memory { + /* Use padding so that each processor's variables are on their own page */ + int pad_begin[PAD_SIZE]; + + real tnow; /* current value of simulation time */ + real tout; /* time next output is due */ + int nstep; /* number of integration steps so far */ + + int workMin, workMax;/* interval of cost to be treated by a proc */ + + vector min, max; /* min and max of coordinates for each Proc. */ + + int mynumcell; /* num. of cells used for this proc in ctab */ + int mynumleaf; /* num. of leaves used for this proc in ctab */ + int mynbody; /* num bodies allocated to the processor */ + bodyptr* mybodytab; /* array of bodies allocated / processor */ + int myncell; /* num cells allocated to the processor */ + cellptr* mycelltab; /* array of cellptrs allocated to the processor */ + int mynleaf; /* number of leaves allocated to the processor */ + leafptr* myleaftab; /* array of leafptrs allocated to the processor */ + cellptr ctab; /* array of cells used for the tree. */ + leafptr ltab; /* array of cells used for the tree. */ + + int myn2bcalc; /* body-body force calculations for each processor */ + int mynbccalc; /* body-cell force calculations for each processor */ + int myselfint; /* count self-interactions for each processor */ + int myn2bterm; /* count body-body terms for a body */ + int mynbcterm; /* count body-cell terms for a body */ + bool skipself; /* true if self-interaction skipped OK */ + bodyptr pskip; /* body to skip in force evaluation */ + vector pos0; /* point at which to evaluate field */ + real phi0; /* computed potential at pos0 */ + vector acc0; /* computed acceleration at pos0 */ + vector dr; /* data to be shared */ + real drsq; /* between gravsub and subdivp */ + nodeptr pmem; /* remember particle data */ + + nodeptr Current_Root; + int Root_Coords[NDIM]; + + real mymtot; /* total mass of N-body system */ + real myetot[3]; /* binding, kinetic, potential energy */ + matrix myketen; /* kinetic energy tensor */ + matrix mypeten; /* potential energy tensor */ + vector mycmphase[2]; /* center of mass coordinates */ + vector myamvec; /* angular momentum vector */ + + int pad_end[PAD_SIZE]; +}; +global struct local_memory Local[MAX_PROC]; + +#endif diff --git a/benchmarks/benchmarks/barnes/code_io.c b/benchmarks/benchmarks/barnes/code_io.c new file mode 100644 index 0000000..01d5948 --- /dev/null +++ b/benchmarks/benchmarks/barnes/code_io.c @@ -0,0 +1,259 @@ +#line 95 "./null_macros/c.m4.null" + +#line 1 "code_io.C" +/*************************************************************************/ +/* */ +/* Copyright (c) 1994 Stanford University */ +/* */ +/* All rights reserved. */ +/* */ +/* Permission is given to use, copy, and modify this software for any */ +/* non-commercial purpose as long as this copyright notice is not */ +/* removed. All other uses, including redistribution in whole or in */ +/* part, are forbidden without prior written permission. */ +/* */ +/* This software is provided with absolutely no warranty and no */ +/* support. */ +/* */ +/*************************************************************************/ + +/* + * CODE_IO.C: + */ + +#define global extern + +#include "code.h" + +void in_int (), in_real (), in_vector (); +void out_int (), out_real (), out_vector (); +void diagnostics (unsigned int ProcessId); + +/* + * INPUTDATA: read initial conditions from input file. + */ + +inputdata () +{ + stream instr; + permanent char headbuf[128]; + int ndim,counter=0; + real tnow; + bodyptr p; + int i; + + fprintf(stderr,"reading input file : %s\n",infile); + fflush(stderr); + instr = fopen(infile, "r"); + if (instr == NULL) + error("inputdata: cannot find file %s\n", infile); + sprintf(headbuf, "Hack code: input file %s\n", infile); + headline = headbuf; + in_int(instr, &nbody); + if (nbody < 1) + error("inputdata: nbody = %d is absurd\n", nbody); + in_int(instr, &ndim); + if (ndim != NDIM) + error("inputdata: NDIM = %d ndim = %d is absurd\n", NDIM,ndim); + in_real(instr, &tnow); + for (i = 0; i < MAX_PROC; i++) { + Local[i].tnow = tnow; + } + bodytab = (bodyptr) malloc(nbody * sizeof(body));; + if (bodytab == NULL) + error("inputdata: not enuf memory\n"); + for (p = bodytab; p < bodytab+nbody; p++) { + Type(p) = BODY; + Cost(p) = 1; + Phi(p) = 0.0; + CLRV(Acc(p)); + } + for (p = bodytab; p < bodytab+nbody; p++) + in_real(instr, &Mass(p)); + for (p = bodytab; p < bodytab+nbody; p++) + in_vector(instr, Pos(p)); + for (p = bodytab; p < bodytab+nbody; p++) + in_vector(instr, Vel(p)); + fclose(instr); +} + +/* + * INITOUTPUT: initialize output routines. + */ + + +initoutput() +{ + printf("\n\t\t%s\n\n", headline); + printf("%10s%10s%10s%10s%10s%10s%10s%10s\n", + "nbody", "dtime", "eps", "tol", "dtout", "tstop","fcells","NPROC"); + printf("%10d%10.5f%10.4f%10.2f%10.3f%10.3f%10.2f%10d\n\n", + nbody, dtime, eps, tol, dtout, tstop, fcells, NPROC); +} + +/* + * STOPOUTPUT: finish up after a run. + */ + + +/* + * OUTPUT: compute diagnostics and output data. + */ + +void +output (ProcessId) + unsigned int ProcessId; +{ + int nttot, nbavg, ncavg,k; + double cputime(); + bodyptr p, *pp; + vector tempv1,tempv2; + + if ((Local[ProcessId].tout - 0.01 * dtime) <= Local[ProcessId].tnow) { + Local[ProcessId].tout += dtout; + } + + diagnostics(ProcessId); + + if (Local[ProcessId].mymtot!=0) { + {;}; + Global->n2bcalc += Local[ProcessId].myn2bcalc; + Global->nbccalc += Local[ProcessId].mynbccalc; + Global->selfint += Local[ProcessId].myselfint; + ADDM(Global->keten, Global-> keten, Local[ProcessId].myketen); + ADDM(Global->peten, Global-> peten, Local[ProcessId].mypeten); + for (k=0;k<3;k++) Global->etot[k] += Local[ProcessId].myetot[k]; + ADDV(Global->amvec, Global-> amvec, Local[ProcessId].myamvec); + + MULVS(tempv1, Global->cmphase[0],Global->mtot); + MULVS(tempv2, Local[ProcessId].mycmphase[0], Local[ProcessId].mymtot); + ADDV(tempv1, tempv1, tempv2); + DIVVS(Global->cmphase[0], tempv1, Global->mtot+Local[ProcessId].mymtot); + + MULVS(tempv1, Global->cmphase[1],Global->mtot); + MULVS(tempv2, Local[ProcessId].mycmphase[1], Local[ProcessId].mymtot); + ADDV(tempv1, tempv1, tempv2); + DIVVS(Global->cmphase[1], tempv1, Global->mtot+Local[ProcessId].mymtot); + Global->mtot +=Local[ProcessId].mymtot; + {;}; + } + + {;}; + + if (ProcessId==0) { + nttot = Global->n2bcalc + Global->nbccalc; + nbavg = (int) ((real) Global->n2bcalc / (real) nbody); + ncavg = (int) ((real) Global->nbccalc / (real) nbody); + } +} + + + +/* + * DIAGNOSTICS: compute set of dynamical diagnostics. + */ + +void +diagnostics (ProcessId) + unsigned int ProcessId; +{ + register bodyptr p,*pp; + real velsq; + vector tmpv; + matrix tmpt; + + Local[ProcessId].mymtot = 0.0; + Local[ProcessId].myetot[1] = Local[ProcessId].myetot[2] = 0.0; + CLRM(Local[ProcessId].myketen); + CLRM(Local[ProcessId].mypeten); + CLRV(Local[ProcessId].mycmphase[0]); + CLRV(Local[ProcessId].mycmphase[1]); + CLRV(Local[ProcessId].myamvec); + for (pp = Local[ProcessId].mybodytab+Local[ProcessId].mynbody -1; + pp >= Local[ProcessId].mybodytab; pp--) { + p= *pp; + Local[ProcessId].mymtot += Mass(p); + DOTVP(velsq, Vel(p), Vel(p)); + Local[ProcessId].myetot[1] += 0.5 * Mass(p) * velsq; + Local[ProcessId].myetot[2] += 0.5 * Mass(p) * Phi(p); + MULVS(tmpv, Vel(p), 0.5 * Mass(p)); + OUTVP(tmpt, tmpv, Vel(p)); + ADDM(Local[ProcessId].myketen, Local[ProcessId].myketen, tmpt); + MULVS(tmpv, Pos(p), Mass(p)); + OUTVP(tmpt, tmpv, Acc(p)); + ADDM(Local[ProcessId].mypeten, Local[ProcessId].mypeten, tmpt); + MULVS(tmpv, Pos(p), Mass(p)); + ADDV(Local[ProcessId].mycmphase[0], Local[ProcessId].mycmphase[0], tmpv); + MULVS(tmpv, Vel(p), Mass(p)); + ADDV(Local[ProcessId].mycmphase[1], Local[ProcessId].mycmphase[1], tmpv); + CROSSVP(tmpv, Pos(p), Vel(p)); + MULVS(tmpv, tmpv, Mass(p)); + ADDV(Local[ProcessId].myamvec, Local[ProcessId].myamvec, tmpv); + } + Local[ProcessId].myetot[0] = Local[ProcessId].myetot[1] + + Local[ProcessId].myetot[2]; + if (Local[ProcessId].mymtot!=0){ + DIVVS(Local[ProcessId].mycmphase[0], Local[ProcessId].mycmphase[0], + Local[ProcessId].mymtot); + DIVVS(Local[ProcessId].mycmphase[1], Local[ProcessId].mycmphase[1], + Local[ProcessId].mymtot); + } +} + + + +/* + * Low-level input and output operations. + */ + +void in_int(str, iptr) + stream str; + int *iptr; +{ + if (fscanf(str, "%d", iptr) != 1) + error("in_int: input conversion error\n"); +} + +void in_real(str, rptr) + stream str; + real *rptr; +{ + double tmp; + + if (fscanf(str, "%lf", &tmp) != 1) + error("in_real: input conversion error\n"); + *rptr = tmp; +} + +void in_vector(str, vec) + stream str; + vector vec; +{ + double tmpx, tmpy, tmpz; + + if (fscanf(str, "%lf%lf%lf", &tmpx, &tmpy, &tmpz) != 3) + error("in_vector: input conversion error\n"); + vec[0] = tmpx; vec[1] = tmpy; vec[2] = tmpz; +} + +void out_int(str, ival) + stream str; + int ival; +{ + fprintf(str, " %d\n", ival); +} + +void out_real(str, rval) + stream str; + real rval; +{ + fprintf(str, " %21.14E\n", rval); +} + +void out_vector(str, vec) + stream str; + vector vec; +{ + fprintf(str, " %21.14E %21.14E", vec[0], vec[1]); + fprintf(str, " %21.14E\n",vec[2]); +} diff --git a/benchmarks/benchmarks/barnes/defs.h b/benchmarks/benchmarks/barnes/defs.h new file mode 100644 index 0000000..b789b41 --- /dev/null +++ b/benchmarks/benchmarks/barnes/defs.h @@ -0,0 +1,318 @@ +#line 95 "./null_macros/c.m4.null" + +#line 1 "defs.H" +/*************************************************************************/ +/* */ +/* Copyright (c) 1994 Stanford University */ +/* */ +/* All rights reserved. */ +/* */ +/* Permission is given to use, copy, and modify this software for any */ +/* non-commercial purpose as long as this copyright notice is not */ +/* removed. All other uses, including redistribution in whole or in */ +/* part, are forbidden without prior written permission. */ +/* */ +/* This software is provided with absolutely no warranty and no */ +/* support. */ +/* */ +/*************************************************************************/ + +#ifndef _DEFS_H_ +#define _DEFS_H_ + +#include "stdinc.h" +#include + +//#include + +#include "vectmath.h" + +#define MAX_PROC 128 +#define MAX_BODIES_PER_LEAF 10 +#define MAXLOCK 2048 /* maximum number of locks on DASH */ +#define PAGE_SIZE 4096 /* in bytes */ + +#define NSUB (1 << NDIM) /* subcells per cell */ + +/* The more complicated 3D case */ +#define NUM_DIRECTIONS 32 +#define BRC_FUC 0 +#define BRC_FRA 1 +#define BRA_FDA 2 +#define BRA_FRC 3 +#define BLC_FDC 4 +#define BLC_FLA 5 +#define BLA_FUA 6 +#define BLA_FLC 7 +#define BUC_FUA 8 +#define BUC_FLC 9 +#define BUA_FUC 10 +#define BUA_FRA 11 +#define BDC_FDA 12 +#define BDC_FRC 13 +#define BDA_FDC 14 +#define BDA_FLA 15 + +#define FRC_BUC 16 +#define FRC_BRA 17 +#define FRA_BDA 18 +#define FRA_BRC 19 +#define FLC_BDC 20 +#define FLC_BLA 21 +#define FLA_BUA 22 +#define FLA_BLC 23 +#define FUC_BUA 24 +#define FUC_BLC 25 +#define FUA_BUC 26 +#define FUA_BRA 27 +#define FDC_BDA 28 +#define FDC_BRC 29 +#define FDA_BDC 30 +#define FDA_BLA 31 + +static int Child_Sequence[NUM_DIRECTIONS][NSUB] = +{ + { 2, 5, 6, 1, 0, 3, 4, 7}, /* BRC_FUC */ + { 2, 5, 6, 1, 0, 7, 4, 3}, /* BRC_FRA */ + { 1, 6, 5, 2, 3, 0, 7, 4}, /* BRA_FDA */ + { 1, 6, 5, 2, 3, 4, 7, 0}, /* BRA_FRC */ + { 6, 1, 2, 5, 4, 7, 0, 3}, /* BLC_FDC */ + { 6, 1, 2, 5, 4, 3, 0, 7}, /* BLC_FLA */ + { 5, 2, 1, 6, 7, 4, 3, 0}, /* BLA_FUA */ + { 5, 2, 1, 6, 7, 0, 3, 4}, /* BLA_FLC */ + { 1, 2, 5, 6, 7, 4, 3, 0}, /* BUC_FUA */ + { 1, 2, 5, 6, 7, 0, 3, 4}, /* BUC_FLC */ + { 6, 5, 2, 1, 0, 3, 4, 7}, /* BUA_FUC */ + { 6, 5, 2, 1, 0, 7, 4, 3}, /* BUA_FRA */ + { 5, 6, 1, 2, 3, 0, 7, 4}, /* BDC_FDA */ + { 5, 6, 1, 2, 3, 4, 7, 0}, /* BDC_FRC */ + { 2, 1, 6, 5, 4, 7, 0, 3}, /* BDA_FDC */ + { 2, 1, 6, 5, 4, 3, 0, 7}, /* BDA_FLA */ + + { 3, 4, 7, 0, 1, 2, 5, 6}, /* FRC_BUC */ + { 3, 4, 7, 0, 1, 6, 5, 2}, /* FRC_BRA */ + { 0, 7, 4, 3, 2, 1, 6, 5}, /* FRA_BDA */ + { 0, 7, 4, 3, 2, 5, 6, 1}, /* FRA_BRC */ + { 7, 0, 3, 4, 5, 6, 1, 2}, /* FLC_BDC */ + { 7, 0, 3, 4, 5, 2, 1, 6}, /* FLC_BLA */ + { 4, 3, 0, 7, 6, 5, 2, 1}, /* FLA_BUA */ + { 4, 3, 0, 7, 6, 1, 2, 5}, /* FLA_BLC */ + { 0, 3, 4, 7, 6, 5, 2, 1}, /* FUC_BUA */ + { 0, 3, 4, 7, 6, 1, 2, 5}, /* FUC_BLC */ + { 7, 4, 3, 0, 1, 2, 5, 6}, /* FUA_BUC */ + { 7, 4, 3, 0, 1, 6, 5, 2}, /* FUA_BRA */ + { 4, 7, 0, 3, 2, 1, 6, 5}, /* FDC_BDA */ + { 4, 7, 0, 3, 2, 5, 6, 1}, /* FDC_BRC */ + { 3, 0, 7, 4, 5, 6, 1, 2}, /* FDA_BDC */ + { 3, 0, 7, 4, 5, 2, 1, 6}, /* FDA_BLA */ +}; + +static int Direction_Sequence[NUM_DIRECTIONS][NSUB] = +{ + { FRC_BUC, BRA_FRC, FDA_BDC, BLA_FUA, BUC_FLC, FUA_BUC, BRA_FRC, FDA_BLA }, + /* BRC_FUC */ + { FRC_BUC, BRA_FRC, FDA_BDC, BLA_FUA, BRA_FDA, FRC_BRA, BUC_FUA, FLC_BDC }, + /* BRC_FRA */ + { FRA_BDA, BRC_FRA, FUC_BUA, BLC_FDC, BDA_FLA, FDC_BDA, BRC_FRA, FUC_BLC }, + /* BRA_FDA */ + { FRA_BDA, BRC_FRA, FUC_BUA, BLC_FDC, BUC_FLC, FUA_BUC, BRA_FRC, FDA_BLA }, + /* BRA_FRC */ + { FLC_BDC, BLA_FLC, FUA_BUC, BRA_FDA, BDC_FRC, FDA_BDC, BLA_FLC, FUA_BRA }, + /* BLC_FDC */ + { FLC_BDC, BLA_FLC, FUA_BUC, BRA_FDA, BLA_FUA, FLC_BLA, BDC_FDA, FRC_BUC }, + /* BLC_FLA */ + { FLA_BUA, BLC_FLA, FDC_BDA, BRC_FUC, BUA_FRA, FUC_BUA, BLC_FLA, FDC_BRC }, + /* BLA_FUA */ + { FLA_BUA, BLC_FLA, FDC_BDA, BRC_FUC, BLC_FDC, FLA_BLC, BUA_FUC, FRA_BDA }, + /* BLA_FLC */ + { FUC_BLC, BUA_FUC, FRA_BRC, BDA_FLA, BUA_FRA, FUC_BUA, BLC_FLA, FDC_BRC }, + /* BUC_FUA */ + { FUC_BLC, BUA_FUC, FRA_BRC, BDA_FLA, BLC_FDC, FLA_BLC, BUA_FUC, FRA_BDA }, + /* BUC_FLC */ + { FUA_BRA, BUC_FUA, FLC_BLA, BDC_FRC, BUC_FLC, FUA_BUC, BRA_FRC, FDA_BLA }, + /* BUA_FUC */ + { FUA_BRA, BUC_FUA, FLC_BLA, BDC_FRC, BRA_FDA, FRC_BRA, BUC_FUA, FLC_BDC }, + /* BUA_FRA */ + { FDC_BRC, BDA_FDC, FLA_BLC, BUA_FRA, BDA_FLA, FDC_BDA, BRC_FRA, FUC_BLC }, + /* BDC_FDA */ + { FDC_BRC, BDA_FDC, FLA_BLC, BUA_FRA, BUC_FLC, FUA_BUC, BRA_FRC, FDA_BLA }, + /* BDC_FRC */ + { FDA_BLA, BDC_FDA, FRC_BRA, BUC_FLC, BDC_FRC, FDA_BDC, BLA_FLC, FUA_BRA }, + /* BDA_FDC */ + { FDA_BLA, BDC_FDA, FRC_BRA, BUC_FLC, BLA_FUA, FLC_BLA, BDC_FDA, FRC_BUC }, + /* BDA_FLA */ + + { BUC_FLC, FUA_BUC, BRA_FRC, FDA_BLA, FUC_BLC, BUA_FUC, FRA_BRC, BDA_FLA }, + /* FRC_BUC */ + { BUC_FLC, FUA_BUC, BRA_FRC, FDA_BLA, FRA_BDA, BRC_FRA, FUC_BUA, BLC_FDC }, + /* FRC_BRA */ + { BRA_FDA, FRC_BRA, BUC_FUA, FLC_BDC, FDA_BLA, BDC_FDA, FRC_BRA, BUC_FLC }, + /* FRA_BDA */ + { BRA_FDA, FRC_BRA, BUC_FUA, FLC_BDC, FRC_BUC, BRA_FRC, FDA_BDC, BLA_FUA }, + /* FRA_BRC */ + { BLC_FDC, FLA_BLC, BUA_FUC, FRA_BDA, FDC_BRC, BDA_FDC, FLA_BLC, BUA_FRA }, + /* FLC_BDC */ + { BLC_FDC, FLA_BLC, BUA_FUC, FRA_BDA, FLA_BUA, BLC_FLA, FDC_BDA, BRC_FUC }, + /* FLC_BLA */ + { BLA_FUA, FLC_BLA, BDC_FDA, FRC_BUC, FUA_BRA, BUC_FUA, FLC_BLA, BDC_FRC }, + /* FLA_BUA */ + { BLA_FUA, FLC_BLA, BDC_FDA, FRC_BUC, FLC_BDC, BLA_FLC, FUA_BUC, BRA_FDA }, + /* FLA_BLC */ + { BUC_FLC, FUA_BUC, BRA_FRC, FDA_BLA, FUA_BRA, BUC_FUA, FLC_BLA, BDC_FRC }, + /* FUC_BUA */ + { BUC_FLC, FUA_BUC, BRA_FRC, FDA_BLA, FLC_BDC, BLA_FLC, FUA_BUC, BRA_FDA }, + /* FUC_BLC */ + { BUA_FRA, FUC_BUA, BLC_FLA, FDC_BRC, FUC_BLC, BUA_FUC, FRA_BRC, BDA_FLA }, + /* FUA_BUC */ + { BUA_FRA, FUC_BUA, BLC_FLA, FDC_BRC, FRA_BDA, BRC_FRA, FUC_BUA, BLC_FDC }, + /* FUA_BRA */ + { BDC_FRC, FDA_BDC, BLA_FLC, FUA_BRA, FDA_BLA, BDC_FDA, FRC_BRA, BUC_FLC }, + /* FDC_BDA */ + { BDC_FRC, FDA_BDC, BLA_FLC, FUA_BRA, FRC_BUC, BRA_FRC, FDA_BDC, BLA_FUA }, + /* FDC_BRC */ + { BDA_FLA, FDC_BDA, BRC_FRA, FUC_BLC, FDC_BRC, BDA_FDC, FLA_BLC, BUA_FRA }, + /* FDA_BDC */ + { BDA_FLA, FDC_BDA, BRC_FRA, FUC_BLC, FLA_BUA, BLC_FLA, FDC_BDA, BRC_FUC }, + /* FDA_BLA */ +}; + +/* + * BODY and CELL data structures are used to represent the tree: + * + * +-----------------------------------------------------------+ + * root--> | CELL: mass, pos, cost, quad, /, o, /, /, /, /, o, /, done | + * +---------------------------------|--------------|----------+ + * | | + * +--------------------------------------+ | + * | | + * | +--------------------------------------+ | + * +--> | BODY: mass, pos, cost, vel, acc, phi | | + * +--------------------------------------+ | + * | + * +-----------------------------------------------------+ + * | + * | +-----------------------------------------------------------+ + * +--> | CELL: mass, pos, cost, quad, o, /, /, o, /, /, o, /, done | + * +------------------------------|--------|--------|----------+ + * etc etc etc + */ + +/* + * NODE: data common to BODY and CELL structures. + */ + +typedef struct _node { + short type; /* code for node type: body or cell */ + real mass; /* total mass of node */ + vector pos; /* position of node */ + int cost; /* number of interactions computed */ + int level; + struct _node *parent; /* ptr to parent of this node in tree */ + int child_num; /* Index that this node should be put + at in parent cell */ +} node; + +typedef node* nodeptr; + +#define Type(x) (((nodeptr) (x))->type) +#define Mass(x) (((nodeptr) (x))->mass) +#define Pos(x) (((nodeptr) (x))->pos) +#define Cost(x) (((nodeptr) (x))->cost) +#define Level(x) (((nodeptr) (x))->level) +#define Parent(x) (((nodeptr) (x))->parent) +#define ChildNum(x) (((nodeptr) (x))->child_num) + +/* + * BODY: data structure used to represent particles. + */ + +typedef struct _body* bodyptr; +typedef struct _leaf* leafptr; +typedef struct _cell* cellptr; + +#define BODY 01 /* type code for bodies */ + +typedef struct _body { + short type; + real mass; /* mass of body */ + vector pos; /* position of body */ + int cost; /* number of interactions computed */ + int level; + leafptr parent; + int child_num; /* Index that this node should be put */ + vector vel; /* velocity of body */ + vector acc; /* acceleration of body */ + real phi; /* potential at body */ +} body; + +#define Vel(x) (((bodyptr) (x))->vel) +#define Acc(x) (((bodyptr) (x))->acc) +#define Phi(x) (((bodyptr) (x))->phi) + +/* + * CELL: structure used to represent internal nodes of tree. + */ + +#define CELL 02 /* type code for cells */ + +typedef struct _cell { + short type; + real mass; /* total mass of cell */ + vector pos; /* cm. position of cell */ + int cost; /* number of interactions computed */ + int level; + cellptr parent; + int child_num; /* Index [0..8] that this node should be put */ + int processor; /* Used by partition code */ + struct _cell *next, *prev; /* Used in the partition array */ + unsigned long seqnum; +#ifdef QUADPOLE + matrix quad; /* quad. moment of cell */ +#endif + volatile short int done; /* flag to tell when the c.of.m is ready */ + nodeptr subp[NSUB]; /* descendents of cell */ +} cell; + +#define Subp(x) (((cellptr) (x))->subp) + +/* + * LEAF: structure used to represent leaf nodes of tree. + */ + +#define LEAF 03 /* type code for leaves */ + +typedef struct _leaf { + short type; + real mass; /* total mass of leaf */ + vector pos; /* cm. position of leaf */ + int cost; /* number of interactions computed */ + int level; + cellptr parent; + int child_num; /* Index [0..8] that this node should be put */ + int processor; /* Used by partition code */ + struct _leaf *next, *prev; /* Used in the partition array */ + unsigned long seqnum; +#ifdef QUADPOLE + matrix quad; /* quad. moment of leaf */ +#endif + volatile short int done; /* flag to tell when the c.of.m is ready */ + unsigned int num_bodies; + bodyptr bodyp[MAX_BODIES_PER_LEAF]; /* bodies of leaf */ +} leaf; + +#define Bodyp(x) (((leafptr) (x))->bodyp) + +#ifdef QUADPOLE +#define Quad(x) (((cellptr) (x))->quad) +#endif +#define Done(x) (((cellptr) (x))->done) + +/* + * Integerized coordinates: used to mantain body-tree. + */ + +#define MAXLEVEL (8*sizeof(int)-2) +#define IMAX (1 << MAXLEVEL) /* highest bit of int coord */ + +#endif + diff --git a/benchmarks/benchmarks/barnes/getparam.c b/benchmarks/benchmarks/barnes/getparam.c new file mode 100644 index 0000000..fd636cf --- /dev/null +++ b/benchmarks/benchmarks/barnes/getparam.c @@ -0,0 +1,174 @@ +#line 95 "./null_macros/c.m4.null" + +#line 1 "getparam.C" +/*************************************************************************/ +/* */ +/* Copyright (c) 1994 Stanford University */ +/* */ +/* All rights reserved. */ +/* */ +/* Permission is given to use, copy, and modify this software for any */ +/* non-commercial purpose as long as this copyright notice is not */ +/* removed. All other uses, including redistribution in whole or in */ +/* part, are forbidden without prior written permission. */ +/* */ +/* This software is provided with absolutely no warranty and no */ +/* support. */ +/* */ +/*************************************************************************/ + +/* + * GETPARAM.C: + */ + + +#include "stdinc.h" + +local string *defaults = NULL; /* vector of "name=value" strings */ + +/* + * INITPARAM: ignore arg vector, remember defaults. + */ + +initparam(argv, defv) + string *argv, *defv; +{ + defaults = defv; +} + +/* + * GETPARAM: export version prompts user for value. + */ + +string getparam(name) + string name; /* name of parameter */ +{ + int scanbind(), i, strlen(), leng; + string extrvalue(), def; + char buf[128], *strcpy(); + char* temp; + + if (defaults == NULL) + error("getparam: called before initparam\n"); + i = scanbind(defaults, name); + if (i < 0) + error("getparam: %s unknown\n", name); + def = extrvalue(defaults[i]); + gets(buf); + leng = strlen(buf) + 1; + if (leng > 1) { + return (strcpy(malloc(leng), buf)); + } + else { + return (def); + } +} + +/* + * GETIPARAM, ..., GETDPARAM: get int, long, bool, or double parameters. + */ + +int getiparam(name) + string name; /* name of parameter */ +{ + string getparam(), val; + int atoi(); + + for (val = ""; *val == NULL;) { + val = getparam(name); + } + return (atoi(val)); +} + +long getlparam(name) + string name; /* name of parameter */ +{ + string getparam(), val; + long atol(); + + for (val = ""; *val == NULL; ) + val = getparam(name); + return (atol(val)); +} + +bool getbparam(name) + string name; /* name of parameter */ +{ + string getparam(), val; + + for (val = ""; *val == NULL; ) + val = getparam(name); + if (strchr("tTyY1", *val) != NULL) { + return (TRUE); + } + if (strchr("fFnN0", *val) != NULL) { + return (FALSE); + } + error("getbparam: %s=%s not bool\n", name, val); +} + +double getdparam(name) + string name; /* name of parameter */ +{ + string getparam(), val; + double atof(); + + for (val = ""; *val == NULL; ) { + val = getparam(name); + } + return (atof(val)); +} + + + +/* + * SCANBIND: scan binding vector for name, return index. + */ + +int scanbind(bvec, name) + string bvec[]; + string name; +{ + int i; + bool matchname(); + + for (i = 0; bvec[i] != NULL; i++) + if (matchname(bvec[i], name)) + return (i); + return (-1); +} + +/* + * MATCHNAME: determine if "name=value" matches "name". + */ + +bool matchname(bind, name) + string bind, name; +{ + char *bp, *np; + + bp = bind; + np = name; + while (*bp == *np) { + bp++; + np++; + } + return (*bp == '=' && *np == NULL); +} + +/* + * EXTRVALUE: extract value from name=value string. + */ + +string extrvalue(arg) + string arg; /* string of the form "name=value" */ +{ + char *ap; + + ap = (char *) arg; + while (*ap != NULL) + if (*ap++ == '=') + return ((string) ap); + return (NULL); +} + diff --git a/benchmarks/benchmarks/barnes/grav.c b/benchmarks/benchmarks/barnes/grav.c new file mode 100644 index 0000000..426d05f --- /dev/null +++ b/benchmarks/benchmarks/barnes/grav.c @@ -0,0 +1,173 @@ +#line 95 "./null_macros/c.m4.null" + +#line 1 "grav.C" +/*************************************************************************/ +/* */ +/* Copyright (c) 1994 Stanford University */ +/* */ +/* All rights reserved. */ +/* */ +/* Permission is given to use, copy, and modify this software for any */ +/* non-commercial purpose as long as this copyright notice is not */ +/* removed. All other uses, including redistribution in whole or in */ +/* part, are forbidden without prior written permission. */ +/* */ +/* This software is provided with absolutely no warranty and no */ +/* support. */ +/* */ +/*************************************************************************/ + +/* + * GRAV.C: + */ + + +#define global extern + +#include "code.h" + +/* + * HACKGRAV: evaluate grav field at a given particle. + */ + +hackgrav(p,ProcessId) + bodyptr p; + unsigned ProcessId; + +{ + extern gravsub(); + + Local[ProcessId].pskip = p; + SETV(Local[ProcessId].pos0, Pos(p)); + Local[ProcessId].phi0 = 0.0; + CLRV(Local[ProcessId].acc0); + Local[ProcessId].myn2bterm = 0; + Local[ProcessId].mynbcterm = 0; + Local[ProcessId].skipself = FALSE; + hackwalk(gravsub, ProcessId); + Phi(p) = Local[ProcessId].phi0; + SETV(Acc(p), Local[ProcessId].acc0); +#ifdef QUADPOLE + Cost(p) = Local[ProcessId].myn2bterm + NDIM * Local[ProcessId].mynbcterm; +#else + Cost(p) = Local[ProcessId].myn2bterm + Local[ProcessId].mynbcterm; +#endif +} + + + +/* + * GRAVSUB: compute a single body-body or body-cell interaction. + */ + +gravsub(p, ProcessId, level) + register nodeptr p; /* body or cell to interact with */ + unsigned ProcessId; + int level; +{ + double sqrt(); + real drabs, phii, mor3; + vector ai, quaddr; + real dr5inv, phiquad, drquaddr; + + if (p != Local[ProcessId].pmem) { + SUBV(Local[ProcessId].dr, Pos(p), Local[ProcessId].pos0); + DOTVP(Local[ProcessId].drsq, Local[ProcessId].dr, Local[ProcessId].dr); + } + + Local[ProcessId].drsq += epssq; + drabs = sqrt((double) Local[ProcessId].drsq); + phii = Mass(p) / drabs; + Local[ProcessId].phi0 -= phii; + mor3 = phii / Local[ProcessId].drsq; + MULVS(ai, Local[ProcessId].dr, mor3); + ADDV(Local[ProcessId].acc0, Local[ProcessId].acc0, ai); + if(Type(p) != BODY) { /* a body-cell/leaf interaction? */ + Local[ProcessId].mynbcterm++; +#ifdef QUADPOLE + dr5inv = 1.0/(Local[ProcessId].drsq * Local[ProcessId].drsq * drabs); + MULMV(quaddr, Quad(p), Local[ProcessId].dr); + DOTVP(drquaddr, Local[ProcessId].dr, quaddr); + phiquad = -0.5 * dr5inv * drquaddr; + Local[ProcessId].phi0 += phiquad; + phiquad = 5.0 * phiquad / Local[ProcessId].drsq; + MULVS(ai, Local[ProcessId].dr, phiquad); + SUBV(Local[ProcessId].acc0, Local[ProcessId].acc0, ai); + MULVS(quaddr, quaddr, dr5inv); + SUBV(Local[ProcessId].acc0, Local[ProcessId].acc0, quaddr); +#endif + } + else { /* a body-body interaction */ + Local[ProcessId].myn2bterm++; + } +} + +/* + * HACKWALK: walk the tree opening cells too close to a given point. + */ + +local proced hacksub; + +hackwalk(sub, ProcessId) + proced sub; /* routine to do calculation */ + unsigned ProcessId; +{ + walksub(Global->G_root, Global->rsize * Global->rsize, ProcessId); +} + +/* + * WALKSUB: recursive routine to do hackwalk operation. + */ + +walksub(n, dsq, ProcessId) + nodeptr n; /* pointer into body-tree */ + real dsq; /* size of box squared */ + unsigned ProcessId; +{ + bool subdivp(); + nodeptr* nn; + leafptr l; + bodyptr p; + int i; + + if (subdivp(n, dsq, ProcessId)) { + if (Type(n) == CELL) { + for (nn = Subp(n); nn < Subp(n) + NSUB; nn++) { + if (*nn != NULL) { + walksub(*nn, dsq / 4.0, ProcessId); + } + } + } + else { + l = (leafptr) n; + for (i = 0; i < l->num_bodies; i++) { + p = Bodyp(l)[i]; + if (p != Local[ProcessId].pskip) { + gravsub(p, ProcessId); + } + else { + Local[ProcessId].skipself = TRUE; + } + } + } + } + else { + gravsub(n, ProcessId); + } +} + +/* + * SUBDIVP: decide if a node should be opened. + * Side effects: sets pmem,dr, and drsq. + */ + +bool subdivp(p, dsq, ProcessId) + register nodeptr p; /* body/cell to be tested */ + real dsq; /* size of cell squared */ + unsigned ProcessId; +{ + SUBV(Local[ProcessId].dr, Pos(p), Local[ProcessId].pos0); + DOTVP(Local[ProcessId].drsq, Local[ProcessId].dr, Local[ProcessId].dr); + Local[ProcessId].pmem = p; + return (tolsq * Local[ProcessId].drsq < dsq); +} diff --git a/benchmarks/benchmarks/barnes/input b/benchmarks/benchmarks/barnes/input new file mode 100644 index 0000000..8e566fc --- /dev/null +++ b/benchmarks/benchmarks/barnes/input @@ -0,0 +1,12 @@ + +163840 +123 + +0.025 +0.05 +1.0 +2.0 +5.0 +0.075 +0.25 +1 diff --git a/benchmarks/benchmarks/barnes/load.c b/benchmarks/benchmarks/barnes/load.c new file mode 100644 index 0000000..ecd4054 --- /dev/null +++ b/benchmarks/benchmarks/barnes/load.c @@ -0,0 +1,557 @@ +#line 95 "./null_macros/c.m4.null" + +#line 1 "load.C" +/*************************************************************************/ +/* */ +/* Copyright (c) 1994 Stanford University */ +/* */ +/* All rights reserved. */ +/* */ +/* Permission is given to use, copy, and modify this software for any */ +/* non-commercial purpose as long as this copyright notice is not */ +/* removed. All other uses, including redistribution in whole or in */ +/* part, are forbidden without prior written permission. */ +/* */ +/* This software is provided with absolutely no warranty and no */ +/* support. */ +/* */ +/*************************************************************************/ + + +#define global extern + +#include "code.h" +#include "defs.h" + +bool intcoord(); +cellptr makecell(unsigned int ProcessId); +leafptr makeleaf(unsigned int ProcessId); +cellptr SubdivideLeaf(leafptr le, cellptr parent, unsigned int l, + unsigned int ProcessId); + +cellptr InitCell(cellptr parent, unsigned int ProcessId); +leafptr InitLeaf(cellptr parent, unsigned int ProcessId); +nodeptr loadtree(bodyptr p, cellptr root, unsigned int ProcessId); + +/* + * MAKETREE: initialize tree structure for hack force calculation. + */ + +maketree(ProcessId) + unsigned ProcessId; +{ + bodyptr p, *pp; + + Local[ProcessId].myncell = 0; + Local[ProcessId].mynleaf = 0; + if (ProcessId == 0) { + Local[ProcessId].mycelltab[Local[ProcessId].myncell++] = Global->G_root; + } + Local[ProcessId].Current_Root = (nodeptr) Global->G_root; + for (pp = Local[ProcessId].mybodytab; + pp < Local[ProcessId].mybodytab+Local[ProcessId].mynbody; pp++) { + p = *pp; + if (Mass(p) != 0.0) { + Local[ProcessId].Current_Root + = (nodeptr) loadtree(p, (cellptr) Local[ProcessId].Current_Root, + ProcessId); + } + else { + {;}; + fprintf(stderr, "Process %d found body %d to have zero mass\n", + ProcessId, (int) p); + {;}; + } + } + {;}; + hackcofm( 0, ProcessId ); + {;}; +} + +cellptr InitCell(parent, ProcessId) + cellptr parent; + unsigned ProcessId; +{ + cellptr c; + int i, Mycell; + + c = makecell(ProcessId); + c->processor = ProcessId; + c->next = NULL; + c->prev = NULL; + if (parent == NULL) + Level(c) = IMAX >> 1; + else + Level(c) = Level(parent) >> 1; + Parent(c) = (nodeptr) parent; + ChildNum(c) = 0; + return (c); +} + +leafptr InitLeaf(parent, ProcessId) + cellptr parent; + unsigned ProcessId; +{ + leafptr l; + int i, Mycell; + + l = makeleaf(ProcessId); + l->processor = ProcessId; + l->next = NULL; + l->prev = NULL; + if (parent==NULL) + Level(l) = IMAX >> 1; + else + Level(l) = Level(parent) >> 1; + Parent(l) = (nodeptr) parent; + ChildNum(l) = 0; + return (l); +} + +printtree (n) + nodeptr n; +{ + int k; + cellptr c; + leafptr l; + bodyptr p; + nodeptr tmp; + unsigned long nseq; + int xp[NDIM]; + + switch (Type(n)) { + case CELL: + c = (cellptr) n; + nseq = c->seqnum; + printf("Cell : Cost = %d, ", Cost(c)); + PRTV("Pos", Pos(n)); + printf("\n"); + for (k = 0; k < NSUB; k++) { + printf("Child #%d: ", k); + if (Subp(c)[k] == NULL) { + printf("NONE"); + } + else { + if (Type(Subp(c)[k]) == CELL) { + nseq = ((cellptr) Subp(c)[k])->seqnum; + printf("C: Cost = %d, ", Cost(Subp(c)[k])); + } + else { + nseq = ((leafptr) Subp(c)[k])->seqnum; + printf("L: # Bodies = %2d, Cost = %d, ", + ((leafptr) Subp(c)[k])->num_bodies, Cost(Subp(c)[k])); + } + tmp = Subp(c)[k]; + PRTV("Pos", Pos(tmp)); + } + printf("\n"); + } + for (k=0;kseqnum; + printf("Leaf : # Bodies = %2d, Cost = %d, ", l->num_bodies, Cost(l)); + PRTV("Pos", Pos(n)); + printf("\n"); + for (k = 0; k < l->num_bodies; k++) { + p = Bodyp(l)[k]; + printf("Body #%2d: Num = %2d, Level = %o, ", + p - bodytab, k, Level(p)); + PRTV("Pos",Pos(p)); + printf("\n"); + } + break; + default: + fprintf(stderr, "Bad type\n"); + exit(-1); + break; + } + fflush(stdout); +} + +/* + * LOADTREE: descend tree and insert particle. + */ + +nodeptr +loadtree(p, root, ProcessId) + bodyptr p; /* body to load into tree */ + cellptr root; + unsigned ProcessId; +{ + int l, xq[NDIM], xp[NDIM], xor[NDIM], subindex(), flag; + int i, j, root_level; + bool valid_root; + int kidIndex; + volatile nodeptr *volatile qptr, mynode; + cellptr c; + leafptr le; + + intcoord(xp, Pos(p)); + valid_root = TRUE; + for (i = 0; i < NDIM; i++) { + xor[i] = xp[i] ^ Local[ProcessId].Root_Coords[i]; + } + for (i = IMAX >> 1; i > Level(root); i >>= 1) { + for (j = 0; j < NDIM; j++) { + if (xor[j] & i) { + valid_root = FALSE; + break; + } + } + if (!valid_root) { + break; + } + } + if (!valid_root) { + if (root != Global->G_root) { + root_level = Level(root); + for (j = i; j > root_level; j >>= 1) { + root = (cellptr) Parent(root); + } + valid_root = TRUE; + for (i = IMAX >> 1; i > Level(root); i >>= 1) { + for (j = 0; j < NDIM; j++) { + if (xor[j] & i) { + valid_root = FALSE; + break; + } + } + if (!valid_root) { + printf("P%d body %d\n", ProcessId, p - bodytab); + root = Global->G_root; + } + } + } + } + root = Global->G_root; + mynode = (nodeptr) root; + kidIndex = subindex(xp, Level(mynode)); + qptr = &Subp(mynode)[kidIndex]; + + l = Level(mynode) >> 1; + + flag = TRUE; + while (flag) { /* loop descending tree */ + if (l == 0) { + error("not enough levels in tree\n"); + } + if (*qptr == NULL) { + /* lock the parent cell */ + {;}; + if (*qptr == NULL) { + le = InitLeaf((cellptr) mynode, ProcessId); + Parent(p) = (nodeptr) le; + Level(p) = l; + ChildNum(p) = le->num_bodies; + ChildNum(le) = kidIndex; + Bodyp(le)[le->num_bodies++] = p; + *qptr = (nodeptr) le; + flag = FALSE; + } + {;}; + /* unlock the parent cell */ + } + if (flag && *qptr && (Type(*qptr) == LEAF)) { + /* reached a "leaf"? */ + {;}; + /* lock the parent cell */ + if (Type(*qptr) == LEAF) { /* still a "leaf"? */ + le = (leafptr) *qptr; + if (le->num_bodies == MAX_BODIES_PER_LEAF) { + *qptr = (nodeptr) SubdivideLeaf(le, (cellptr) mynode, l, + ProcessId); + } + else { + Parent(p) = (nodeptr) le; + Level(p) = l; + ChildNum(p) = le->num_bodies; + Bodyp(le)[le->num_bodies++] = p; + flag = FALSE; + } + } + {;}; + /* unlock the node */ + } + if (flag) { + mynode = *qptr; + kidIndex = subindex(xp, l); + qptr = &Subp(*qptr)[kidIndex]; /* move down one level */ + l = l >> 1; /* and test next bit */ + } + } + SETV(Local[ProcessId].Root_Coords, xp); + return Parent((leafptr) *qptr); +} + + +/* * INTCOORD: compute integerized coordinates. * Returns: TRUE +unless rp was out of bounds. */ + +bool intcoord(xp, rp) + int xp[NDIM]; /* integerized coordinate vector [0,IMAX) */ + vector rp; /* real coordinate vector (system coords) */ +{ + int k; + bool inb; + double xsc, floor(); + + inb = TRUE; + for (k = 0; k < NDIM; k++) { + xsc = (rp[k] - Global->rmin[k]) / Global->rsize; + if (0.0 <= xsc && xsc < 1.0) { + xp[k] = floor(IMAX * xsc); + } + else { + inb = FALSE; + } + } + return (inb); +} + +/* + * SUBINDEX: determine which subcell to select. + */ + +int subindex(x, l) + int x[NDIM]; /* integerized coordinates of particle */ + int l; /* current level of tree */ +{ + int i, k; + int yes; + + i = 0; + yes = FALSE; + if (x[0] & l) { + i += NSUB >> 1; + yes = TRUE; + } + for (k = 1; k < NDIM; k++) { + if (((x[k] & l) && !yes) || (!(x[k] & l) && yes)) { + i += NSUB >> (k + 1); + yes = TRUE; + } + else yes = FALSE; + } + + return (i); +} + + + +/* + * HACKCOFM: descend tree finding center-of-mass coordinates. + */ + +hackcofm(nc, ProcessId) + int nc; + unsigned ProcessId; +{ + int i,Myindex; + nodeptr r; + leafptr l; + leafptr* ll; + bodyptr p; + cellptr q; + cellptr *cc; + vector tmpv, dr; + real drsq; + matrix drdr, Idrsq, tmpm; + + /* get a cell using get*sub. Cells are got in reverse of the order in */ + /* the cell array; i.e. reverse of the order in which they were created */ + /* this way, we look at child cells before parents */ + + for (ll = Local[ProcessId].myleaftab + Local[ProcessId].mynleaf - 1; + ll >= Local[ProcessId].myleaftab; ll--) { + l = *ll; + Mass(l) = 0.0; + Cost(l) = 0; + CLRV(Pos(l)); + for (i = 0; i < l->num_bodies; i++) { + p = Bodyp(l)[i]; + Mass(l) += Mass(p); + Cost(l) += Cost(p); + MULVS(tmpv, Pos(p), Mass(p)); + ADDV(Pos(l), Pos(l), tmpv); + } + DIVVS(Pos(l), Pos(l), Mass(l)); +#ifdef QUADPOLE + CLRM(Quad(l)); + for (i = 0; i < l->num_bodies; i++) { + p = Bodyp(l)[i]; + SUBV(dr, Pos(p), Pos(l)); + OUTVP(drdr, dr, dr); + DOTVP(drsq, dr, dr); + SETMI(Idrsq); + MULMS(Idrsq, Idrsq, drsq); + MULMS(tmpm, drdr, 3.0); + SUBM(tmpm, tmpm, Idrsq); + MULMS(tmpm, tmpm, Mass(p)); + ADDM(Quad(l), Quad(l), tmpm); + } +#endif + Done(l)=TRUE; + } + for (cc = Local[ProcessId].mycelltab+Local[ProcessId].myncell-1; + cc >= Local[ProcessId].mycelltab; cc--) { + q = *cc; + Mass(q) = 0.0; + Cost(q) = 0; + CLRV(Pos(q)); + for (i = 0; i < NSUB; i++) { + r = Subp(q)[i]; + if (r != NULL) { + while(!Done(r)) { + /* wait */ + } + Mass(q) += Mass(r); + Cost(q) += Cost(r); + MULVS(tmpv, Pos(r), Mass(r)); + ADDV(Pos(q), Pos(q), tmpv); + Done(r) = FALSE; + } + } + DIVVS(Pos(q), Pos(q), Mass(q)); +#ifdef QUADPOLE + CLRM(Quad(q)); + for (i = 0; i < NSUB; i++) { + r = Subp(q)[i]; + if (r != NULL) { + SUBV(dr, Pos(r), Pos(q)); + OUTVP(drdr, dr, dr); + DOTVP(drsq, dr, dr); + SETMI(Idrsq); + MULMS(Idrsq, Idrsq, drsq); + MULMS(tmpm, drdr, 3.0); + SUBM(tmpm, tmpm, Idrsq); + MULMS(tmpm, tmpm, Mass(r)); + ADDM(tmpm, tmpm, Quad(r)); + ADDM(Quad(q), Quad(q), tmpm); + } + } +#endif + Done(q)=TRUE; + } +} + +cellptr +SubdivideLeaf (le, parent, l, ProcessId) + leafptr le; + cellptr parent; + unsigned int l; + unsigned int ProcessId; +{ + cellptr c; + int i, index; + int xp[NDIM]; + bodyptr bodies[MAX_BODIES_PER_LEAF]; + int num_bodies; + bodyptr p; + + /* first copy leaf's bodies to temp array, so we can reuse the leaf */ + num_bodies = le->num_bodies; + for (i = 0; i < num_bodies; i++) { + bodies[i] = Bodyp(le)[i]; + Bodyp(le)[i] = NULL; + } + le->num_bodies = 0; + /* create the parent cell for this subtree */ + c = InitCell(parent, ProcessId); + ChildNum(c) = ChildNum(le); + /* do first particle separately, so we can reuse le */ + p = bodies[0]; + intcoord(xp, Pos(p)); + index = subindex(xp, l); + Subp(c)[index] = (nodeptr) le; + ChildNum(le) = index; + Parent(le) = (nodeptr) c; + Level(le) = l >> 1; + /* set stuff for body */ + Parent(p) = (nodeptr) le; + ChildNum(p) = le->num_bodies; + Level(p) = l >> 1; + /* insert the body */ + Bodyp(le)[le->num_bodies++] = p; + /* now handle the rest */ + for (i = 1; i < num_bodies; i++) { + p = bodies[i]; + intcoord(xp, Pos(p)); + index = subindex(xp, l); + if (!Subp(c)[index]) { + le = InitLeaf(c, ProcessId); + ChildNum(le) = index; + Subp(c)[index] = (nodeptr) le; + } + else { + le = (leafptr) Subp(c)[index]; + } + Parent(p) = (nodeptr) le; + ChildNum(p) = le->num_bodies; + Level(p) = l >> 1; + Bodyp(le)[le->num_bodies++] = p; + } + return c; +} + +/* + * MAKECELL: allocation routine for cells. + */ + +cellptr makecell(ProcessId) + unsigned ProcessId; +{ + cellptr c; + int i, Mycell; + + if (Local[ProcessId].mynumcell == maxmycell) { + error("makecell: Proc %d needs more than %d cells; increase fcells\n", + ProcessId,maxmycell); + } + Mycell = Local[ProcessId].mynumcell++; + c = Local[ProcessId].ctab + Mycell; + c->seqnum = ProcessId*maxmycell+Mycell; + Type(c) = CELL; + Done(c) = FALSE; + Mass(c) = 0.0; + for (i = 0; i < NSUB; i++) { + Subp(c)[i] = NULL; + } + Local[ProcessId].mycelltab[Local[ProcessId].myncell++] = c; + return (c); +} + +/* + * MAKELEAF: allocation routine for leaves. + */ + +leafptr makeleaf(ProcessId) + unsigned ProcessId; +{ + leafptr le; + int i, Myleaf; + + if (Local[ProcessId].mynumleaf == maxmyleaf) { + error("makeleaf: Proc %d needs more than %d leaves; increase fleaves\n", + ProcessId,maxmyleaf); + } + Myleaf = Local[ProcessId].mynumleaf++; + le = Local[ProcessId].ltab + Myleaf; + le->seqnum = ProcessId * maxmyleaf + Myleaf; + Type(le) = LEAF; + Done(le) = FALSE; + Mass(le) = 0.0; + le->num_bodies = 0; + for (i = 0; i < MAX_BODIES_PER_LEAF; i++) { + Bodyp(le)[i] = NULL; + } + Local[ProcessId].myleaftab[Local[ProcessId].mynleaf++] = le; + return (le); +} + + diff --git a/benchmarks/benchmarks/barnes/stdinc.h b/benchmarks/benchmarks/barnes/stdinc.h new file mode 100644 index 0000000..c2310f4 --- /dev/null +++ b/benchmarks/benchmarks/barnes/stdinc.h @@ -0,0 +1,119 @@ +#line 95 "./null_macros/c.m4.null" + +#line 1 "stdinc.H" +/*************************************************************************/ +/* */ +/* Copyright (c) 1994 Stanford University */ +/* */ +/* All rights reserved. */ +/* */ +/* Permission is given to use, copy, and modify this software for any */ +/* non-commercial purpose as long as this copyright notice is not */ +/* removed. All other uses, including redistribution in whole or in */ +/* part, are forbidden without prior written permission. */ +/* */ +/* This software is provided with absolutely no warranty and no */ +/* support. */ +/* */ +/*************************************************************************/ + +/* + * STDINC.H: standard include file for C programs. + */ + +#ifndef _STDINC_H_ +#define _STDINC_H_ + +/* + * If not already loaded, include stdio.h. + */ + +#include + +/* + * STREAM: a replacement for FILE *. + */ + +typedef FILE *stream; + +/* + * NULL: denotes a pointer to no object. + */ + +#ifndef NULL +#define NULL 0 +#endif + +/* + * BOOL, TRUE and FALSE: standard names for logical values. + */ + +typedef int bool; + +#ifndef TRUE + +#define FALSE 0 +#define TRUE 1 + +#endif + +/* + * BYTE: a short name for a handy chunk of bits. + */ + +typedef unsigned char byte; + +/* + * STRING: for null-terminated strings which are not taken apart. + */ + +typedef char *string; + +/* + * REAL: default type is double; + */ + +typedef double real, *realptr; + +/* + * PROC, IPROC, RPROC: pointers to procedures, integer functions, and + * real-valued functions, respectively. + */ + +typedef void (*proced)(); +typedef int (*iproc)(); +typedef real (*rproc)(); + +/* + * LOCAL: declare something to be local to a file. + * PERMANENT: declare something to be permanent data within a function. + */ + +#define local static +#define permanent static + +/* + * STREQ: handy string-equality macro. + */ + +#define streq(x,y) (strcmp((x), (y)) == 0) + +/* + * PI, etc. -- mathematical constants + */ + +#define PI 3.14159265358979323846 +#define TWO_PI 6.28318530717958647693 +#define FOUR_PI 12.56637061435917295385 +#define HALF_PI 1.57079632679489661923 +#define FRTHRD_PI 4.18879020478639098462 + +/* + * ABS: returns the absolute value of its argument + * MAX: returns the argument with the highest value + * MIN: returns the argument with the lowest value + */ + +#define ABS(x) (((x) < 0) ? -(x) : (x)) + +#endif diff --git a/benchmarks/benchmarks/barnes/util.c b/benchmarks/benchmarks/barnes/util.c new file mode 100644 index 0000000..34fd195 --- /dev/null +++ b/benchmarks/benchmarks/barnes/util.c @@ -0,0 +1,103 @@ +#line 95 "./null_macros/c.m4.null" + +#line 1 "util.C" +/*************************************************************************/ +/* */ +/* Copyright (c) 1994 Stanford University */ +/* */ +/* All rights reserved. */ +/* */ +/* Permission is given to use, copy, and modify this software for any */ +/* non-commercial purpose as long as this copyright notice is not */ +/* removed. All other uses, including redistribution in whole or in */ +/* part, are forbidden without prior written permission. */ +/* */ +/* This software is provided with absolutely no warranty and no */ +/* support. */ +/* */ +/*************************************************************************/ + +#include +#include +#include "stdinc.h" + +#define HZ 60.0 +#define MULT 1103515245 +#define ADD 12345 +#define MASK (0x7FFFFFFF) +#define TWOTO31 2147483648.0 + +local int A = 1; +local int B = 0; +local int randx = 1; +local int lastrand; /* the last random number */ + +/* + * XRAND: generate floating-point random number. + */ + +double prand(); + +double xrand(xl, xh) + double xl, xh; /* lower, upper bounds on number */ +{ + long random (); + double x; + + return (xl + (xh - xl) * prand()); +} + +void pranset(int seed) +{ + int proc; + + A = 1; + B = 0; + randx = (A*seed+B) & MASK; + A = (MULT * A) & MASK; + B = (MULT*B + ADD) & MASK; +} + +double +prand() +/* + Return a random double in [0, 1.0) +*/ +{ + lastrand = randx; + randx = (A*randx+B) & MASK; + return((double)lastrand/TWOTO31); +} + +/* + * CPUTIME: compute CPU time in min. + */ + +#include +#include + + +double cputime() +{ + struct tms buffer; + + if (times(&buffer) == -1) + error("times() call failed\n"); + return (buffer.tms_utime / (60.0 * HZ)); +} + +/* + * ERROR: scream and die quickly. + */ + +error(msg, a1, a2, a3, a4) + char *msg, *a1, *a2, *a3, *a4; +{ + extern int errno; + + fprintf(stderr, msg, a1, a2, a3, a4); + if (errno != 0) + perror("Error"); + exit(0); +} + diff --git a/benchmarks/benchmarks/barnes/vectmath.h b/benchmarks/benchmarks/barnes/vectmath.h new file mode 100644 index 0000000..0828b99 --- /dev/null +++ b/benchmarks/benchmarks/barnes/vectmath.h @@ -0,0 +1,308 @@ +#line 95 "./null_macros/c.m4.null" + +#line 1 "vectmath.H" +/*************************************************************************/ +/* */ +/* Copyright (c) 1994 Stanford University */ +/* */ +/* All rights reserved. */ +/* */ +/* Permission is given to use, copy, and modify this software for any */ +/* non-commercial purpose as long as this copyright notice is not */ +/* removed. All other uses, including redistribution in whole or in */ +/* part, are forbidden without prior written permission. */ +/* */ +/* This software is provided with absolutely no warranty and no */ +/* support. */ +/* */ +/*************************************************************************/ + +/* + * VECTMATH.H: include file for vector/matrix operations. + */ + +#ifndef _VECMATH_H_ +#define _VECMATH_H_ + + + +# define NDIM 3 + +typedef real vector[NDIM], matrix[NDIM][NDIM]; + +/* + * Vector operations. + */ + +#define CLRV(v) /* CLeaR Vector */ \ +{ \ + register int _i; \ + for (_i = 0; _i < NDIM; _i++) \ + (v)[_i] = 0.0; \ +} + +#define UNITV(v,j) /* UNIT Vector */ \ +{ \ + register int _i; \ + for (_i = 0; _i < NDIM; _i++) \ + (v)[_i] = (_i == (j) ? 1.0 : 0.0); \ +} + +#define SETV(v,u) /* SET Vector */ \ +{ \ + register int _i; \ + for (_i = 0; _i < NDIM; _i++) \ + (v)[_i] = (u)[_i]; \ +} + + +#define ADDV(v,u,w) /* ADD Vector */ \ +{ \ + register real *_vp = (v), *_up = (u), *_wp = (w); \ + *_vp++ = (*_up++) + (*_wp++); \ + *_vp++ = (*_up++) + (*_wp++); \ + *_vp = (*_up ) + (*_wp ); \ +} + +#define SUBV(v,u,w) /* SUBtract Vector */ \ +{ \ + register real *_vp = (v), *_up = (u), *_wp = (w); \ + *_vp++ = (*_up++) - (*_wp++); \ + *_vp++ = (*_up++) - (*_wp++); \ + *_vp = (*_up ) - (*_wp ); \ +} + +#define MULVS(v,u,s) /* MULtiply Vector by Scalar */ \ +{ \ + register real *_vp = (v), *_up = (u); \ + *_vp++ = (*_up++) * (s); \ + *_vp++ = (*_up++) * (s); \ + *_vp = (*_up ) * (s); \ +} + + +#define DIVVS(v,u,s) /* DIVide Vector by Scalar */ \ +{ \ + register int _i; \ + for (_i = 0; _i < NDIM; _i++) \ + (v)[_i] = (u)[_i] / (s); \ +} + + +#define DOTVP(s,v,u) /* DOT Vector Product */ \ +{ \ + register real *_vp = (v), *_up = (u); \ + (s) = (*_vp++) * (*_up++); \ + (s) += (*_vp++) * (*_up++); \ + (s) += (*_vp ) * (*_up ); \ +} + + +#define ABSV(s,v) /* ABSolute value of a Vector */ \ +{ \ + double _tmp, sqrt(); \ + register int _i; \ + _tmp = 0.0; \ + for (_i = 0; _i < NDIM; _i++) \ + _tmp += (v)[_i] * (v)[_i]; \ + (s) = sqrt(_tmp); \ +} + +#define DISTV(s,u,v) /* DISTance between Vectors */ \ +{ \ + double _tmp, sqrt(); \ + register int _i; \ + _tmp = 0.0; \ + for (_i = 0; _i < NDIM; _i++) \ + _tmp += ((u)[_i]-(v)[_i]) * ((u)[_i]-(v)[_i]); \ + (s) = sqrt(_tmp); \ +} + + + +#define CROSSVP(v,u,w) /* CROSS Vector Product */ \ +{ \ + (v)[0] = (u)[1]*(w)[2] - (u)[2]*(w)[1]; \ + (v)[1] = (u)[2]*(w)[0] - (u)[0]*(w)[2]; \ + (v)[2] = (u)[0]*(w)[1] - (u)[1]*(w)[0]; \ +} + + +#define INCADDV(v,u) /* INCrementally ADD Vector */ \ +{ \ + register int _i; \ + for (_i = 0; _i < NDIM; _i++) \ + (v)[_i] += (u)[_i]; \ +} + +#define INCSUBV(v,u) /* INCrementally SUBtract Vector */ \ +{ \ + register int _i; \ + for (_i = 0; _i < NDIM; _i++) \ + (v)[_i] -= (u)[_i]; \ +} + +#define INCMULVS(v,s) /* INCrementally MULtiply Vector by Scalar */ \ +{ \ + register int _i; \ + for (_i = 0; _i < NDIM; _i++) \ + (v)[_i] *= (s); \ +} + +#define INCDIVVS(v,s) /* INCrementally DIVide Vector by Scalar */ \ +{ \ + register int _i; \ + for (_i = 0; _i < NDIM; _i++) \ + (v)[_i] /= (s); \ +} + +/* + * Matrix operations. + */ + +#define CLRM(p) /* CLeaR Matrix */ \ +{ \ + register int _i, _j; \ + for (_i = 0; _i < NDIM; _i++) \ + for (_j = 0; _j < NDIM; _j++) \ + (p)[_i][_j] = 0.0; \ +} + +#define SETMI(p) /* SET Matrix to Identity */ \ +{ \ + register int _i, _j; \ + for (_i = 0; _i < NDIM; _i++) \ + for (_j = 0; _j < NDIM; _j++) \ + (p)[_i][_j] = (_i == _j ? 1.0 : 0.0); \ +} + +#define SETM(p,q) /* SET Matrix */ \ +{ \ + register int _i, _j; \ + for (_i = 0; _i < NDIM; _i++) \ + for (_j = 0; _j < NDIM; _j++) \ + (p)[_i][_j] = (q)[_i][_j]; \ +} + +#define TRANM(p,q) /* TRANspose Matrix */ \ +{ \ + register int _i, _j; \ + for (_i = 0; _i < NDIM; _i++) \ + for (_j = 0; _j < NDIM; _j++) \ + (p)[_i][_j] = (q)[_j][_i]; \ +} + +#define ADDM(p,q,r) /* ADD Matrix */ \ +{ \ + register int _i, _j; \ + for (_i = 0; _i < NDIM; _i++) \ + for (_j = 0; _j < NDIM; _j++) \ + (p)[_i][_j] = (q)[_i][_j] + (r)[_i][_j]; \ +} + +#define SUBM(p,q,r) /* SUBtract Matrix */ \ +{ \ + register int _i, _j; \ + for (_i = 0; _i < NDIM; _i++) \ + for (_j = 0; _j < NDIM; _j++) \ + (p)[_i][_j] = (q)[_i][_j] - (r)[_i][_j]; \ +} + +#define MULM(p,q,r) /* Multiply Matrix */ \ +{ \ + register int _i, _j, _k; \ + for (_i = 0; _i < NDIM; _i++) \ + for (_j = 0; _j < NDIM; _j++) { \ + (p)[_i][_j] = 0.0; \ + for (_k = 0; _k < NDIM; _k++) \ + (p)[_i][_j] += (q)[_i][_k] * (r)[_k][_j]; \ + } \ +} + +#define MULMS(p,q,s) /* MULtiply Matrix by Scalar */ \ +{ \ + register int _i, _j; \ + for (_i = 0; _i < NDIM; _i++) \ + for (_j = 0; _j < NDIM; _j++) \ + (p)[_i][_j] = (q)[_i][_j] * (s); \ +} + +#define DIVMS(p,q,s) /* DIVide Matrix by Scalar */ \ +{ \ + register int _i, _j; \ + for (_i = 0; _i < NDIM; _i++) \ + for (_j = 0; _j < NDIM; _j++) \ + (p)[_i][_j] = (q)[_i][_j] / (s); \ +} + +#define MULMV(v,p,u) /* MULtiply Matrix by Vector */ \ +{ \ + register int _i, _j; \ + for (_i = 0; _i < NDIM; _i++) { \ + (v)[_i] = 0.0; \ + for (_j = 0; _j < NDIM; _j++) \ + (v)[_i] += (p)[_i][_j] * (u)[_j]; \ + } \ +} + +#define OUTVP(p,v,u) /* OUTer Vector Product */ \ +{ \ + register int _i, _j; \ + for (_i = 0; _i < NDIM; _i++) \ + for (_j = 0; _j < NDIM; _j++) \ + (p)[_i][_j] = (v)[_i] * (u)[_j]; \ +} + +#define TRACEM(s,p) /* TRACE of Matrix */ \ +{ \ + register int _i; \ + (s) = 0.0; \ + for (_i = 0.0; _i < NDIM; _i++) \ + (s) += (p)[_i][_i]; \ +} + +/* + * Misc. impure operations. + */ + +#define SETVS(v,s) /* SET Vector to Scalar */ \ +{ \ + register int _i; \ + for (_i = 0; _i < NDIM; _i++) \ + (v)[_i] = (s); \ +} + +#define ADDVS(v,u,s) /* ADD Vector and Scalar */ \ +{ \ + register int _i; \ + for (_i = 0; _i < NDIM; _i++) \ + (v)[_i] = (u)[_i] + (s); \ +} + +#define SETMS(p,s) /* SET Matrix to Scalar */ \ +{ \ + register int _i, _j; \ + for (_i = 0; _i < NDIM; _i++) \ + for (_j = 0; _j < NDIM; _j++) \ + (p)[_i][_j] = (s); \ +} + +#define PRTV(name, vec) /* PRinT Vector */ \ +{ \ + fprintf(stdout,"%s = [%9.4f,%9.4f,%9.4f] ",name,vec[0],vec[1],vec[2]); \ +} +#define PRIV(name, vec) /* PRint Integer Vector */ \ +{ \ + fprintf(stdout,"%s = [%d,%d,%d] ",name,vec[0],vec[1],vec[2]); \ +} +#define PROV(name, vec) /* PRint Integer Vector */ \ +{ \ + fprintf(stdout,"%s = [%o,%o,%o] ",name,vec[0],vec[1],vec[2]); \ +} +#define PRHV(name, vec) /* PRint Integer Vector */ \ +{ \ + fprintf(stdout,"%s = [%x,%x,%x] ",name,vec[0],vec[1],vec[2]); \ +} + +#endif + diff --git a/benchmarks/benchmarks/cfrac/README.md b/benchmarks/benchmarks/cfrac/README.md new file mode 100644 index 0000000..529480a --- /dev/null +++ b/benchmarks/benchmarks/cfrac/README.md @@ -0,0 +1,5 @@ +pcfrac: Implementation of the continued fraction factoring algoritm + +Every two digits additional appears to double the factoring time + +Written by Dave Barrett (barrett%asgard@boulder.Colorado.EDU) diff --git a/benchmarks/benchmarks/cfrac/asm16bit.h b/benchmarks/benchmarks/cfrac/asm16bit.h new file mode 100644 index 0000000..2fb6e48 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/asm16bit.h @@ -0,0 +1,39 @@ +/* + * HP-UX C compiler conventions + * + * Args pushed right-to-left; caller pops args on return + * Function result returned in d0 or d0(msb) d1(lsb) pair + * Called function must preserve all registers except d0,d1,a0,a1 + * C Registers are allocated from top-to-bottem in text from d7-d2, a5-a2 + */ +#ifdef __STDC__ +extern digit memaddw(digitPtr, digitPtr, digitPtr, posit); +extern digit memsubw(digitPtr, digitPtr, digitPtr, posit); + +extern digit memincw(digitPtr, accumulator); +extern digit memdecw(digitPtr, accumulator); + +extern digit memmulw(digitPtr, digitPtr, posit, digitPtr, posit); + +extern digit memdivw(digitPtr, digitPtr, posit, digitPtr); +extern digit memdivw1(digitPtr, digitPtr, posit, digit); +extern digit memmulw1(digitPtr, digitPtr, posit, digit); +extern digit memmodw1(digitPtr, posit, digit); + +extern void memlsrw(digitPtr, posit); +#else +extern digit memaddw(); +extern digit memsubw(); + +extern digit memincw(); +extern digit memdecw(); + +extern digit memmulw(); + +extern digit memdivw(); +extern digit memdivw1(); +extern digit memmulw1(); +extern digit memmodw1(); + +extern void memlsrw(); +#endif diff --git a/benchmarks/benchmarks/cfrac/atop.c b/benchmarks/benchmarks/cfrac/atop.c new file mode 100644 index 0000000..98f132a --- /dev/null +++ b/benchmarks/benchmarks/cfrac/atop.c @@ -0,0 +1,61 @@ +#include +#include "pdefs.h" +#include "pcvt.h" +#include "precision.h" + +/* + * ascii to precision (modeled after atoi) + * leading whitespace skipped + * an optional leading '-' or '+' followed by digits '0'..'9' + * leading 0's Ok + * stops at first unrecognized character + * + * Returns: pUndef if an invalid argument (pUndef or nondigit as 1st digit) + */ +precision atop(chp) + register char *chp; +{ + precision res = pUndef; + precision clump = pUndef; + int sign = 0; + register int ch; + register accumulator temp; + accumulator x; + register int i; + + if (chp != (char *) 0) { + while (isspace(*chp)) chp++; /* skip whitespace */ + if (*chp == '-') { + sign = 1; + ++chp; + } else if (*chp == '+') { + ++chp; + } + if (isdigit(ch = * (unsigned char *) chp)) { + pset(&res, pzero); + pset(&clump, utop(aDigit)); + do { + i = aDigitLog-1; + temp = ch - '0'; + do { + if (!isdigit(ch = * (unsigned char *) ++chp)) goto atoplast; + temp = temp * aBase + (ch - '0'); + } while (--i > 0); + pset(&res, padd(pmul(res, clump), utop(temp))); + } while (isdigit(ch = * (unsigned char *) ++chp)); + goto atopdone; +atoplast: + x = aBase; + while (i++ < aDigitLog-1) { + x *= aBase; + } + pset(&res, padd(pmul(res, utop(x)), utop(temp))); +atopdone: + if (sign) { + pset(&res, pneg(res)); + } + } + } + pdestroy(clump); + return presult(res); +} diff --git a/benchmarks/benchmarks/cfrac/cfrac.c b/benchmarks/benchmarks/cfrac/cfrac.c new file mode 100644 index 0000000..9185d18 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/cfrac.c @@ -0,0 +1,268 @@ +#include +#include +#include /* for findk */ + +#if defined(_WIN32) +#include +#endif + +#include "pdefs.h" + +#ifdef __STDC__ +#include +#endif +#include "precision.h" +#include "pfactor.h" + +#ifdef __STDC__ +extern unsigned *pfactorbase(precision n, unsigned k, + unsigned *m, unsigned aborts); +extern double pomeranceLpow(double n, double alpha); +#else +extern unsigned *pfactorbase(); +extern double pomeranceLpow(); +#endif + +int verbose = 0; +int debug = 0; + +extern unsigned cfracNabort; +extern unsigned cfracTsolns; +extern unsigned cfracPsolns; +extern unsigned cfracT2solns; +extern unsigned cfracFsolns; + + +extern unsigned short primes[]; +extern unsigned primesize; + +/* + * Return the value of "f(p,d)" from Knuth's exercise 28 + */ +float pfKnuthEx28(p, d) + unsigned p; + precision d; +{ + register float res; + precision k = pUndef; + + (void) pparm(d); + if (p == 2) { + if (peven(d)) { + pset(&k, phalf(d)); + if (peven(k)) { + res = 2.0/3.0 + pfKnuthEx28(2,k)/2.0; /* eliminate powers of 2 */ + } else { /* until only one 2 left in d. */ + res = 1.0/3.0; /* independent of (the now odd) k. Wow! */ + } + } else { /* d now odd */ + pset(&k, phalf(d)); + if (podd(k)) { + res = 1.0/3.0; /* f(2,4k+3): d%8 == 3 or 7 */ + } else { + if (podd(phalf(k))) { + res = 2.0/3.0; /* f(2,8k+5): d%8 == 5 */ + } else { + res = 4.0/3.0; /* f(2,8k+1): d%8 == 1 */ + } + } + } + } else { /* PART 3: p odd, d could still be even (OK) */ + pset(&k, utop(p)); + if peq(ppowmod(d, phalf(psub(k, pone)), k), pone) { + res = (float) (p+p) / (((float) p)*p-1.0); /* beware int overflow! */ + } else { + res = 0.0; + } + } + + pdestroy(k); + pdestroy(d); + if (debug > 1) { + fprintf(stdout, "f(%u,", p); + fprintf(stdout, "d) = %9.7f\n", res); + } + return res; +} + +float cfrac_logf(unsigned p, precision n, unsigned k) +{ + register float res; + + (void) pparm(n); + +#if 0 /* old code for non-float machines; not worth the cost */ + pset(&r, utop(k)); + log2sqrtk = plogb(pipow(r, q >> 1), ptwo); + fplog2p = (f(p,pmul(r,n),q) * plogb(pipow(utop(p),q),ptwo)+(q>>1))/q; +#endif + + res = pfKnuthEx28(p, pmul(itop(k),n)) * log((double) p); + /* res -= log((double) k) * 0.5; */ + + pdestroy(n); + return res; +} + +/* + * Find the best value of k for the given n and m. + * + * Input/Output: + * n - the number to factor + * m - pointer to size of factorbase (0 = select "best" size) + * aborts - the number of early aborts + */ +unsigned findk(n, m, aborts, maxk) + precision n; + register unsigned *m; + unsigned aborts, maxk; +{ + unsigned k, bestk = 0, count, bestcount = 0, maxpm; + float sum, max = -1.0E+15; /* should be small enough */ + unsigned *p; + register unsigned i; + register unsigned short *primePtr; + + (void) pparm(n); + + for (k = 1; k < maxk; k++) { /* maxk should best be m+m? */ + if (debug) { + fputs("kN = ", stdout); + fputp(stdout, pmul(utop(k), n)); putc('\n', stdout); + } + count = *m; + p = pfactorbase(n, k, &count, aborts); + if (p == (unsigned *) 0) { + fprintf(stderr, "couldn't compute factor base in findk\n"); + exit(1); + } + + maxpm = p[count-1]; + + sum = 0.0; + primePtr = primes; + while (*primePtr <= maxpm) { + sum += cfrac_logf((unsigned) *primePtr++, n, k); + } + sum -= log((double) k) * 0.5; + if (verbose > 2) fprintf(stdout, "%u: %5.2f", k, sum); + if (debug) fprintf(stdout, " log(k)/2=%5.2f", log((double) k) * 0.5); + if (verbose > 2) { + fputs("\n", stdout); + fflush(stdout); + } + if (sum > max) { + max = sum; + bestk = k; + bestcount = count; + } +#ifndef IGNOREFREE + free(p); +#endif + } + + *m = bestcount; + pdestroy(n); + return bestk; +} + +extern char *optarg; +extern int optind; + +char *progName; + +extern int getopt(); + +int main(argc, argv) + int argc; + char *argv[]; +{ + unsigned m = 0, k = 0; + unsigned maxCount = 1<<30, count, maxk = 0; + int ch; + precision n = pUndef, f = pUndef; + unsigned aborts = 3; + unsigned *p; + double d; + + progName = *argv; + + while ((ch = getopt(argc, argv, "a:k:i:dv")) != EOF) switch (ch) { + case 'a': + aborts = atoi(optarg); + break; + case 'k': + maxk = atoi(optarg); + break; + case 'i': + maxCount = atoi(optarg); + break; + case 'd': + debug++; + break; + case 'v': + verbose++; + break; + default: +usage: fprintf(stderr, + "usage: %s [-dv] [-a aborts ] [-k maxk ] [-i maxCount ] n [[ m ] k ]\n", + progName); + return 1; + } + argc -= optind; + argv += optind; + + if (argc == 0) { + argc = 1; + static char* argvx[2] = { "17545186520507317056371138836327483792736", NULL }; + argv = argvx; + } + + if (argc < 1 || argc > 3) goto usage; + + pset(&n, atop(*argv++)); --argc; + if (argc) { m = atoi(*argv++); --argc; } + if (argc) { k = atoi(*argv++); --argc; } + + if (k == 0) { + if (maxk == 0) { + maxk = m / 2 + 5; + if (verbose) fprintf(stdout, "maxk = %u\n", maxk); + } + k = findk(n, &m, aborts, maxk); + if (verbose) { + fprintf(stdout, "k = %u\n", k); + } + } + + count = maxCount; + + pcfracInit(m, k, aborts); + + pset(&f, pcfrac(n, &count)); + count = maxCount - count; + if (verbose) { + putc('\n', stdout); + fprintf(stdout, "Iterations : %u\n", count); + fprintf(stdout, "Early Aborts : %u\n", cfracNabort); + fprintf(stdout, "Total Partials : %u\n", cfracTsolns); + fprintf(stdout, "Used Partials : %u\n", cfracT2solns); + fprintf(stdout, "Full Solutions : %u\n", cfracPsolns); + fprintf(stdout, "Factor Attempts: %u\n", cfracFsolns); + } + + if (f != pUndef) { + fputp(stdout, n); + fputs(" = ", stdout); + fputp(stdout, f); + fputs(" * ", stdout); + pdivmod(n, f, &n, pNull); + fputp(stdout, n); + putc('\n', stdout); + } + + pdestroy(f); + pdestroy(n); + + return 0; +} diff --git a/benchmarks/benchmarks/cfrac/errorp.c b/benchmarks/benchmarks/cfrac/errorp.c new file mode 100644 index 0000000..5868aa4 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/errorp.c @@ -0,0 +1,27 @@ +#include +#include "precision.h" + +/* + * Fatal error (user substitutable) + * + * PNOMEM - out of memory (pcreate) + * PREFCOUNT - refcount negative (pdestroy) + * PUNDEFINED - undefined value referenced (all) + * PDOMAIN - domain error + * pdivmod: divide by zero + * psqrt: negative argument + * POVERFLOW - overflow + * itop: too big + */ +precision errorp(errnum, routine, message) + int errnum; + char *routine; + char *message; +{ + fputs(routine, stderr); + fputs(": ", stderr); + fputs(message, stderr); + fputs("\n", stderr); + abort(); /* remove this line if you want */ + return pUndef; +} diff --git a/benchmarks/benchmarks/cfrac/getopt.c b/benchmarks/benchmarks/cfrac/getopt.c new file mode 100644 index 0000000..788c2cb --- /dev/null +++ b/benchmarks/benchmarks/cfrac/getopt.c @@ -0,0 +1,757 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. */ + +/* This tells Alpha OSF/1 not to define a getopt prototype in . + Ditto for AIX 3.2 and . */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#include + +#ifdef HAVE_CONFIG_H +#if defined (emacs) || defined (CONFIG_BROKETS) +/* We use instead of "config.h" so that a compilation + using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h + (which it would do because it found this file in $srcdir). */ +#include +#else +#include "config.h" +#endif +#endif + +#ifndef __STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include + +#ifdef HAVE_STRING_H +#include +#endif + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include +#endif /* GNU C library. */ + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* XXX 1003.2 says this must be 1 before any call. */ +int optind = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include +#define my_index strchr +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char *getenv (); + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +#ifndef __STDC__ +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +#endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +static const char * +_getopt_initialize (optstring) + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (optind == 0) + optstring = _getopt_initialize (optstring); + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc + && (argv[optind][0] != '-' || argv[optind][1] == '\0')) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if ((argv[optind][0] != '-' || argv[optind][1] == '\0')) + { + if (ordering == REQUIRE_ORDER) + return EOF; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if (nameend - nextchar == (int) strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, "%s: option `%s' is ambiguous\n", + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[optind - 1][0], pfound->name); + } + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, "%s: option `%s' requires an argument\n", + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, "%s: unrecognized option `--%s'\n", + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, "%s: unrecognized option `%c%s'\n", + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); + else + fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c); + } + optopt = c; + return '?'; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: option requires an argument -- %c\n", + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/benchmarks/benchmarks/cfrac/getopt.h b/benchmarks/benchmarks/cfrac/getopt.h new file mode 100644 index 0000000..7fc2cca --- /dev/null +++ b/benchmarks/benchmarks/cfrac/getopt.h @@ -0,0 +1,125 @@ +/* Declarations for getopt. + Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if __STDC__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. We used to try to prototype + it if __GNU_LIBRARY__ but that wasn't problem free either (I'm not sure + exactly why), and there is no particular need to prototype it. + We really shouldn't be trampling on the system's namespace at all by + declaring getopt() but that is a bigger issue. */ +extern int getopt (); + +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* not __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/benchmarks/benchmarks/cfrac/itop.c b/benchmarks/benchmarks/cfrac/itop.c new file mode 100644 index 0000000..87d309a --- /dev/null +++ b/benchmarks/benchmarks/cfrac/itop.c @@ -0,0 +1,25 @@ +#include "pdefs.h" +#include "pcvt.h" +#include "precision.h" + +/* + * Integer to Precision + */ +precision itop(i) + register int i; +{ + register digitPtr uPtr; + register precision u = palloc(INTSIZE); + + if (u == pUndef) return u; + + if (u->sign = (i < 0)) i = -i; + uPtr = u->value; + do { + *uPtr++ = modBase(i); + i = divBase(i); + } while (i != 0); + + u->size = (uPtr - u->value); /* normalize */ + return presult(u); +} diff --git a/benchmarks/benchmarks/cfrac/ltop.c b/benchmarks/benchmarks/cfrac/ltop.c new file mode 100644 index 0000000..33eaea5 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/ltop.c @@ -0,0 +1,25 @@ +#include "pdefs.h" +#include "pcvt.h" +#include "precision.h" + +/* + * Long to Precision + */ +precision ltop(l) + register long l; +{ + register digitPtr uPtr; + register precision u = palloc(LONGSIZE); + + if (u == pUndef) return u; + + if (u->sign = (l < 0L)) l = -l; + uPtr = u->value; + do { + *uPtr++ = modBase(l); + l = divBase(l); + } while (l != 0); + + u->size = (uPtr - u->value); /* normalize */ + return presult(u); +} diff --git a/benchmarks/benchmarks/cfrac/pabs.c b/benchmarks/benchmarks/cfrac/pabs.c new file mode 100644 index 0000000..674cf1b --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pabs.c @@ -0,0 +1,22 @@ +#include "pdefs.h" /* private include file */ +#include "precision.h" /* public include file for forward refs */ +#include + +/* + * absolute value + */ +precision pabs(u) + register precision u; +{ + register precision w; + + (void) pparm(u); + w = palloc(u->size); + if (w == pUndef) return w; + + w->sign = false; + (void) memcpy(w->value, u->value, u->size * sizeof(digit)); + + pdestroy(u); + return presult(w); +} diff --git a/benchmarks/benchmarks/cfrac/padd.c b/benchmarks/benchmarks/cfrac/padd.c new file mode 100644 index 0000000..62b93d5 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/padd.c @@ -0,0 +1,94 @@ +#include "pdefs.h" +#include "precision.h" +#include + +#ifdef ASM_16BIT +#include "asm16bit.h" +#endif + +/* + * Add + * + * This will work correctly if -0 is passed as input + */ +precision padd(u, v) + register precision v; +#ifndef ASM_16BIT + precision u; +{ + register digitPtr wPtr, uPtr, vPtr; +#else + register precision u; +{ + register digitPtr wPtr; + digitPtr uPtr; +#endif + precision w; /* function result */ + register accumulator temp; /* 0 <= temp < 2*base */ + register digit carry; /* 0 <= carry <= 1 */ +#ifdef ASM_16BIT + register int size; +#endif + + (void) pparm(u); + (void) pparm(v); + if (u->sign != v->sign) { /* Are we are actually subtracting? */ + w = pUndef; + if (v->sign) { + v->sign = !v->sign; /* can't generate -0 */ + pset(&w, psub(u, v)); + v->sign = !v->sign; + } else { + u->sign = !u->sign; /* can't generate -0 */ + pset(&w, psub(v, u)); + u->sign = !u->sign; + } + } else { + if (u->size < v->size) { /* u is always biggest number */ + w = u; u = v; v = w; + } + + w = palloc(u->size+1); /* there is at most one added digit */ + if (w == pUndef) return w; /* arguments not destroyed */ + + w->sign = u->sign; + + uPtr = u->value; + wPtr = w->value; +#ifndef ASM_16BIT + vPtr = v->value; + carry = 0; + do { /* Add digits in both args */ + temp = *uPtr++ + *vPtr++; /* 0 <= temp < 2*base-1 */ + temp += carry; /* 0 <= temp < 2*base */ + carry = divBase(temp); /* 0 <= carry <= 1 */ + *wPtr++ = modBase(temp); /* mod has positive args */ + } while (vPtr < v->value + v->size); + + while (uPtr < u->value + u->size) { /* propogate carry */ + temp = *uPtr++ + carry; + carry = divBase(temp); + *wPtr++ = modBase(temp); + } + *wPtr = carry; +#else + size = v->size; + temp = u->size - size; + carry = memaddw(wPtr, uPtr, v->value, size); + if (temp > 0) { + memcpy(wPtr + size, uPtr + size, temp * sizeof(digit)); + if (carry) { + carry = memincw(wPtr + size, temp); + } + } + wPtr[u->size] = carry; /* yes, I do mean u->size */ +#endif + if (carry == 0) { + --(w->size); + } + } + + pdestroy(u); + pdestroy(v); + return presult(w); +} diff --git a/benchmarks/benchmarks/cfrac/pcfrac.c b/benchmarks/benchmarks/cfrac/pcfrac.c new file mode 100644 index 0000000..2a0d032 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pcfrac.c @@ -0,0 +1,731 @@ +/* + * pcfrac: Implementation of the continued fraction factoring algoritm + * + * Every two digits additional appears to double the factoring time + * + * Written by Dave Barrett (barrett%asgard@boulder.Colorado.EDU) + */ +#include +#include +#include + +#ifdef __STDC__ +#include +#endif +#include "precision.h" +#include "pfactor.h" + +extern int verbose; + +unsigned cfracNabort = 0; +unsigned cfracTsolns = 0; +unsigned cfracPsolns = 0; +unsigned cfracT2solns = 0; +unsigned cfracFsolns = 0; + +extern unsigned short primes[]; +extern unsigned primesize; + +typedef unsigned *uptr; +typedef uptr uvec; +typedef unsigned char *solnvec; +typedef unsigned char *BitVector; + +typedef struct SolnStruc { + struct SolnStruc *next; + precision x; /* lhs of solution */ + precision t; /* last large prime remaining after factoring */ + precision r; /* accumulated root of pm for powers >= 2 */ + BitVector e; /* bit vector of factorbase powers mod 2 */ +} Soln; + +typedef Soln *SolnPtr; + +#define BPI(x) ((sizeof x[0]) << 3) + +void setBit(bv, bno, value) + register BitVector bv; + register unsigned bno, value; +{ + bv += bno / BPI(bv); + bno %= BPI(bv); + *bv |= ((value != 0) << bno); +} + +unsigned getBit(bv, bno) + register BitVector bv; + register unsigned bno; +{ + register unsigned res; + + bv += bno / BPI(bv); + bno %= BPI(bv); + res = (*bv >> bno) & 1; + + return res; +} + +BitVector newBitVector(value, size) + register solnvec value; + unsigned size; +{ + register BitVector res; + register solnvec vp = value + size; + unsigned msize = ((size + BPI(res)-1) / BPI(res)) * sizeof res[0]; + +#ifdef BWGC + res = (BitVector) gc_malloc(msize); +#else + res = (BitVector) malloc(msize); +#endif + if (res == (BitVector) 0) return res; + + memset(res, '\0', msize); + do { + if (*--vp) { + setBit(res, vp - value, (unsigned) *vp); + } + } while (vp != value); + return res; +} + +void printSoln(stream, prefix, suffix, pm, m, p, t, e) + FILE *stream; + char *prefix, *suffix; + register unsigned *pm, m; + precision p, t; + register solnvec e; +{ + register unsigned i, j = 0; + + for (i = 1; i <= m; i++) j += (e[i] != 0); + + fputs(prefix, stream); + fputp(stream, pparm(p)); fputs(" = ", stream); + if (*e & 1) putc('-', stream); else putc('+', stream); + fputp(stream, pparm(t)); + + if (j >= 1) fputs(" *", stream); + do { + e++; + switch (*e) { + case 0: break; + case 1: fprintf(stream, " %u", *pm); break; + default: + fprintf(stream, " %u^%u", *pm, (unsigned) *e); + } + pm++; + } while (--m); + + fputs(suffix, stream); + fflush(stream); + pdestroy(p); pdestroy(t); +} + +/* + * Combine two solutions + */ +void combineSoln(x, t, e, pm, m, n, bp) + precision *x, *t, n; + uvec pm; + register solnvec e; + unsigned m; + SolnPtr bp; +{ + register unsigned j; + + (void) pparm(n); + if (bp != (SolnPtr) 0) { + pset(x, pmod(pmul(bp->x, *x), n)); + pset(t, pmod(pmul(bp->t, *t), n)); + pset(t, pmod(pmul(bp->r, *t), n)); + e[0] += getBit(bp->e, 0); + } + e[0] &= 1; + for (j = 1; j <= m; j++) { + if (bp != (SolnPtr) 0) e[j] += getBit(bp->e, j); + if (e[j] > 2) { + pset(t, pmod(pmul(*t, + ppowmod(utop(pm[j-1]), utop((unsigned) e[j]>>1), n)), n)); + e[j] &= 1; + } else if (e[j] == 2) { + pset(t, pmod(pmul(*t, utop(pm[j-1])), n)); + e[j] = 0; + } + } + pdestroy(n); +} + +/* + * Create a normalized solution structure from the given inputs + */ +SolnPtr newSoln(n, pm, m, next, x, t, e) + precision n; + unsigned m; + uvec pm; + SolnPtr next; + precision x, t; + solnvec e; +{ +#ifdef BWGC + SolnPtr bp = (SolnPtr) gc_malloc(sizeof (Soln)); +#else + SolnPtr bp = (SolnPtr) malloc(sizeof (Soln)); +#endif + + if (bp != (SolnPtr) 0) { + bp->next = next; + bp->x = pnew(x); + bp->t = pnew(t); + bp->r = pnew(pone); + /* + * normalize e, put the result in bp->r and e + */ + combineSoln(&bp->x, &bp->r, e, pm, m, pparm(n), (SolnPtr) 0); + bp->e = newBitVector(e, m+1); /* BitVector */ + } + + pdestroy(n); + return bp; +} + +void freeSoln(p) + register SolnPtr p; +{ + if (p != (SolnPtr) 0) { + pdestroy(p->x); + pdestroy(p->t); + pdestroy(p->r); +#ifndef IGNOREFREE + free(p->e); /* BitVector */ + free(p); +#endif + } +} + +void freeSolns(p) + register SolnPtr p; +{ + register SolnPtr l; + + while (p != (SolnPtr) 0) { + l = p; + p = p->next; + freeSoln(l); + } +} + +SolnPtr findSoln(sp, t) + register SolnPtr sp; + precision t; +{ + (void) pparm(t); + while (sp != (SolnPtr) 0) { + if peq(sp->t, t) break; + sp = sp->next; + } + pdestroy(t); + return sp; +} + +static unsigned pcfrac_k = 1; +static unsigned pcfrac_m = 0; +static unsigned pcfrac_aborts = 3; + +/* + * Structure for early-abort. Last entry must be <(unsigned *) 0, uUndef> + */ +typedef struct { + unsigned *pm; /* bound check occurs before using this pm entry */ + precision bound; /* max allowable residual to prevent abort */ +} EasEntry; + +typedef EasEntry *EasPtr; + +void freeEas(eas) + EasPtr eas; +{ + register EasPtr ep = eas; + + if (ep != (EasPtr) 0) { + while (ep->pm != 0) { + pdestroy(ep->bound); + ep++; + } +#ifndef IGNOREFREE + free(eas); +#endif + } +} + +/* + * Return Pomerance's L^alpha (L = exp(sqrt(log(n)*log(log(n))))) + */ +double pomeranceLpow(n, y) + double n; + double y; +{ + double lnN = log(n); + double res = exp(y * sqrt(lnN * log(lnN))); + return res; +} + +/* + * Pomerance's value 'a' from page 122 "of Computational methods in Number + * Theory", part 1, 1982. + */ +double cfracA(n, aborts) + double n; + unsigned aborts; +{ + return 1.0 / sqrt(6.0 + 2.0 / ((double) aborts + 1.0)); +} + +/* + * Returns 1 if a is a quadratic residue of odd prime p, + * p-1 if non-quadratic residue, 0 otherwise (gcd(a,p)<>1) + */ +#define plegendre(a,p) ppowmod(a, phalf(psub(p, pone)), p) + +/* + * Create a table of small primes of quadratic residues of n + * + * Input: + * n - the number to be factored + * k - the multiple of n to be factored + * *m - the number of primes to generate (0 to select best) + * aborts - the number of early aborts + * + * Assumes that plegendre # 0, for if it is, that pm is a factor of n. + * This algorithm already assumes you've used trial division to eliminate + * all of these! + * + * Returns: the list of primes actually generated (or (unsigned *) 0 if nomem) + * *m changed to reflect the number of elements in the list + */ +uvec pfactorbase(n, k, m, aborts) + precision n; + unsigned k; + unsigned *m, aborts; +{ + double dn, a; + register unsigned short *primePtr = primes; + register unsigned count = *m; + unsigned maxpm = primes[primesize-1]; + unsigned *res = (uvec) 0, *pm; + precision nk = pnew(pmul(pparm(n), utop(k))); + + if (*m == 0) { /* compute a suitable m */ + dn = ptod(nk); + a = cfracA(dn, aborts); + maxpm = (unsigned) (pomeranceLpow(dn, a) + 0.5); + do { + if ((unsigned) *primePtr++ >= maxpm) break; + } while ((unsigned) *primePtr != 1); + count = primePtr - primes; + primePtr = primes; + } + /* + * This m tends to be too small for small n, and becomes closer to + * optimal as n goes to infinity. For 30 digits, best m is ~1.5 this m. + * For 38 digits, best m appears to be ~1.15 this m. It's appears to be + * better to guess too big than too small. + */ +#ifdef BWGC + res = (uvec) gc_malloc(count * sizeof (unsigned)); +#else + res = (uvec) malloc(count * sizeof (unsigned)); +#endif + if (res == (uvec) 0) goto doneMk; + + pm = res; + *pm++ = (unsigned) *primePtr++; /* two is first element */ + count = 1; + if (count != *m) do { + if (picmp(plegendre(nk, utop((unsigned) *primePtr)), 1) <= 0) { /* 0,1 */ + *pm++ = *primePtr; + count++; + if (count == *m) break; + if ((unsigned) *primePtr >= maxpm) break; + } + ++primePtr; + } while (*primePtr != 1); + *m = count; + +doneMk: + pdestroy(nk); + pdestroy(n); + return res; +} + +/* + * Compute Pomerance's early-abort-stragegy + */ +EasPtr getEas(n, k, pm, m, aborts) + precision n; + unsigned k, *pm, m, aborts; +{ + double x = 1.0 / ((double) aborts + 1.0); + double a = 1.0 / sqrt(6.0 + 2.0 * x); + double ax = a * x, csum = 1.0, tia = 0.0; + double dn, dpval, dbound, ci; + unsigned i, j, pval; + + precision bound = pUndef; + EasPtr eas; + + if (aborts == 0) return (EasPtr) 0; + +#ifdef BWGC + eas = (EasPtr) gc_malloc((aborts+1) * sizeof (EasEntry)); +#else + eas = (EasPtr) malloc((aborts+1) * sizeof (EasEntry)); +#endif + if (eas == (EasPtr) 0) return eas; + + dn = ptod(pmul(utop(k), pparm(n))); /* should this be n ? */ + for (i = 1; i <= aborts; i++) { + eas[i-1].pm = (unsigned *) 0; + eas[i-1].bound = pUndef; + tia += ax; + ci = 4.0 * tia * tia / (double) i; + csum -= ci; + dpval = pomeranceLpow(dn, tia); + dbound = pow(dn, 0.5 * csum); + + pval = (unsigned) (dpval + 0.5); + pset(&bound, dtop(dbound)); + for (j = 0; j < m; j++) { + if (pm[j] >= pval) goto foundpm; + } + break; +foundpm: + if (verbose > 1) { + printf(" Abort %u on p = %u (>=%u) and q > ", i, pm[j], pval); + fputp(stdout, bound); putc('\n', stdout); + fflush(stdout); + } + eas[i-1].pm = &pm[j]; + pset(&eas[i-1].bound, bound); + } + eas[i-1].pm = (unsigned *) 0; + eas[i-1].bound = pUndef; + + pdestroy(bound); + pdestroy(n); + + return eas; +} + +/* + * Factor the argument Qn using the primes in pm. Result stored in exponent + * vector e, and residual factor, f. If non-null, eas points to a list of + * early-abort boundaries. + * + * e is set to the number of times each prime in pm divides v. + * + * Returns: + * -2 - if factoring aborted because of early abort + * -1 - factoring failed + * 0 - if result is a "partial" factoring + * 1 - normal return (a "full" factoring) + */ +int pfactorQ(f, t, pm, e, m, eas) + precision *f; + precision t; + register unsigned *pm; + register solnvec e; + register unsigned m; + EasEntry *eas; +{ + precision maxp = pUndef; + unsigned maxpm = pm[m-1], res = 0; + register unsigned *pp = (unsigned *) 0; + + (void) pparm(t); + + if (eas != (EasEntry *) 0) { + pp = eas->pm; + pset(&maxp, eas->bound); + } + + memset((char *) e, '\0', m * sizeof e[0]); /* looks slow here, but isn't */ + + while (peven(t)) { /* assume 2 1st in pm; save time */ + pset(&t, phalf(t)); + (*e)++; + } + --m; + + do { + e++; pm++; + if (pm == pp) { /* check for early abort */ + if (pgt(t, maxp)) { + res = -2; + goto gotSoln; + } + eas++; + pp = eas->pm; + pset(&maxp, eas->bound); + } + while (pimod(t, (int) *pm) == 0) { + pset(&t, pidiv(t, (int) *pm)); + (*e)++; + } + } while (--m != 0); + res = -1; + if (picmp(t, 1) == 0) { + res = 1; + } else if (picmp(pidiv(t, (int) *pm), maxpm) <= 0) { +#if 0 /* it'll never happen; Honest! If so, pm is incorrect. */ + if (picmp(t, maxpm) <= 0) { + fprintf(stderr, "BUG: partial with t < maxpm! t = "); + fputp(stderr, t); putc('\n', stderr); + } +#endif + res = 0; + } +gotSoln: + pset(f, t); + pdestroy(t); pdestroy(maxp); + return res; +} + +/* + * Attempt to factor n using continued fractions (n must NOT be prime) + * + * n - The number to attempt to factor + * maxCount - if non-null, points to the maximum number of iterations to try. + * + * This algorithm may fail if it get's into a cycle or maxCount expires + * If failed, n is returned. + * + * This algorithm will loop indefinitiely in n is prime. + * + * This an implementation of Morrison and Brillhart's algorithm, with + * Pomerance's early abort strategy, and Knuth's method to find best k. + */ +precision pcfrac(n, maxCount) + precision n; + unsigned *maxCount; +{ + unsigned k = pcfrac_k; + unsigned m = pcfrac_m; + unsigned aborts = pcfrac_aborts; + SolnPtr oddt = (SolnPtr) 0, sp, bp, *b; + EasPtr eas = (EasPtr) 0; + uvec pm = (uvec) 0; + solnvec e = (solnvec) 0; + unsigned bsize, s = 0, count = 0; + register unsigned h, j; + int i; + + precision t = pUndef, + r = pUndef, twog = pUndef, u = pUndef, lastU = pUndef, + Qn = pUndef, lastQn = pUndef, An = pUndef, lastAn = pUndef, + x = pUndef, y = pUndef, qn = pUndef, rn = pUndef; + + precision res = pnew(pparm(n)); /* default res is argument */ + + pm = pfactorbase(n, k, &m, aborts); /* m may have been reduced */ + + bsize = (m+2) * sizeof (SolnPtr); +#ifdef BWGC + b = (SolnPtr *) gc_malloc(bsize); +#else + b = (SolnPtr *) malloc(bsize); +#endif + if (b == (SolnPtr *) 0) goto nomem; + +#ifdef BWGC + e = (solnvec) gc_malloc((m+1) * sizeof e[0]); +#else + e = (solnvec) malloc((m+1) * sizeof e[0]); +#endif + if (e == (solnvec) 0) { +nomem: + errorp(PNOMEM, "pcfrac", "out of memory"); + goto bail; + } + + memset(b, '\0', bsize); /* F1: Initialize */ + if (maxCount != (unsigned *) 0) count = *maxCount; + cfracTsolns = cfracPsolns = cfracT2solns = cfracFsolns = cfracNabort = 0; + + eas = getEas(n, k, pm, m, aborts); /* early abort strategy */ + + if (verbose > 1) { + fprintf(stdout, "factorBase[%u]: ", m); + for (j = 0; j < m; j++) { + fprintf(stdout, "%u ", pm[j]); + } + putc('\n', stdout); + fflush(stdout); + } + + pset(&t, pmul(utop(k), n)); /* E1: Initialize */ + pset(&r, psqrt(t)); /* constant: sqrt(k*n) */ + pset(&twog, padd(r, r)); /* constant: 2*sqrt(k*n) */ + pset(&u, twog); /* g + Pn */ + pset(&lastU, twog); + pset(&Qn, pone); + pset(&lastQn, psub(t, pmul(r, r))); + pset(&An, pone); + pset(&lastAn, r); + pset(&qn, pzero); + + do { +F2: + do { + if (--count == 0) goto bail; + pset(&t, An); + pdivmod(padd(pmul(qn, An), lastAn), n, pNull, &An); /* (5) */ + pset(&lastAn, t); + + pset(&t, Qn); + pset(&Qn, padd(pmul(qn, psub(lastU, u)), lastQn)); /* (7) */ + pset(&lastQn, t); + + pset(&lastU, u); + + pset(&qn, pone); /* eliminate 40% of next divmod */ + pset(&rn, psub(u, Qn)); + if (pge(rn, Qn)) { + pdivmod(u, Qn, &qn, &rn); /* (4) */ + } + pset(&u, psub(twog, rn)); /* (6) */ + s = 1-s; + + e[0] = s; + i = pfactorQ(&t, Qn, pm, &e[1], m, eas); /* E3: Factor Qn */ + if (i < -1) cfracNabort++; + /* + * We should (but don't, yet) check to see if we can get a + * factor by a special property of Qn = 1 + */ + if (picmp(Qn, 1) == 0) { + errorp(PDOMAIN, "pcfrac", "cycle encountered; pick bigger k"); + goto bail; /* we ran into a cycle; give up */ + } + } while (i < 0); /* while not a solution */ + + pset(&x, An); /* End of Algorithm E; we now have solution: */ + + if (i == 0) { /* if partial */ + if ((sp = findSoln(oddt, t)) == (SolnPtr) 0) { + cfracTsolns++; + if (verbose >= 2) putc('.', stderr); + if (verbose > 3) printSoln(stdout, "Partial: ","\n", pm,m,x,t,e); + oddt = newSoln(n, pm, m, oddt, x, t, e); + goto F2; /* wait for same t to occur again */ + } + if (verbose > 3) printSoln(stdout, "Partial: ", " -->\n", pm,m,x,t,e); + pset(&t, pone); /* take square root */ + combineSoln(&x, &t, e, pm, m, n, sp); + cfracT2solns++; + if (verbose) putc('#', stderr); + if (verbose > 2) printSoln(stdout, "PartSum: ", "", pm, m, x, t, e); + } else { + combineSoln(&x, &t, e, pm, m, n, (SolnPtr) 0); /* normalize */ + cfracPsolns++; + if (verbose) putc('*', stderr); + if (verbose > 2) printSoln(stdout, "Full: ", "", pm, m, x, t, e); + } + + /* + * Crude gaussian elimination. We should be more effecient about the + * binary vectors here, but this works as it is. + * + * At this point, t must be pone, or t occurred twice + * + * Loop Invariants: e[0:h] even + * t^2 is a product of squares of primes + * b[h]->e[0:h-1] even and b[h]->e[h] odd + */ + h = m+1; + do { + --h; + if (e[h]) { /* F3: Search for odd */ + bp=b[h]; + if (bp == (SolnPtr) 0) { /* F4: Linear dependence? */ + if (verbose > 3) { + printSoln(stdout, " -->\nFullSum: ", "", pm, m, x, t, e); + } + if (verbose > 2) putc('\n', stdout); + b[h] = newSoln(n, pm, m, bp, x, t, e); + goto F2; + } + combineSoln(&x, &t, e, pm, m, n, bp); + } + } while (h != 0); + /* + * F5: Try to Factor: We have a perfect square (has about 50% chance) + */ + cfracFsolns++; + pset(&y, t); /* t is already sqrt'd */ + + switch (verbose) { + case 0: break; + case 1: putc('/', stderr); break; + case 2: putc('\n', stderr); break; + default: ; + putc('\n', stderr); + printSoln(stdout, " -->\nSquare: ", "\n", pm, m, x, t, e); + fputs("x,y: ", stdout); + fputp(stdout, x); fputs(" ", stdout); + fputp(stdout, y); putc('\n', stdout); + fflush(stdout); + } + } while (peq(x, y) || peq(padd(x, y), n)); /* while x = +/- y */ + + pset(&res, pgcd(padd(x, y), n)); /* factor found at last */ + + /* + * Check for degenerate solution. This shouldn't happen. Detects bugs. + */ + if (peq(res, pone) || peq(res, n)) { + fputs("Error! Degenerate solution:\n", stdout); + fputs("x,y: ", stdout); + fputp(stdout, x); fputs(" ", stdout); + fputp(stdout, y); putc('\n', stdout); + fflush(stdout); + abort(); + } + +bail: + if (maxCount != (unsigned *) 0) *maxCount = count; + + if (b != (SolnPtr *) 0) for (j = 0; j <= m; j++) freeSoln(b[j]); + freeEas(eas); + freeSolns(oddt); +#ifndef IGNOREFREE + free(e); + free(pm); +#endif + + pdestroy(r); pdestroy(twog); pdestroy(u); pdestroy(lastU); + pdestroy(Qn); pdestroy(lastQn); pdestroy(An); pdestroy(lastAn); + pdestroy(x); pdestroy(y); pdestroy(qn); pdestroy(rn); + pdestroy(t); pdestroy(n); + + return presult(res); +} + +/* + * Initialization for pcfrac factoring method + * + * k - An integer multiplier to use for n (k must be < n) + * you can use findk to get a good value. k should be squarefree + * m - The number of primes to use in the factor base + * aborts - the number of early aborts to use + */ +int pcfracInit(m, k, aborts) + unsigned m; + unsigned k; + unsigned aborts; +{ + pcfrac_m = m; + pcfrac_k = k; + pcfrac_aborts = aborts; + return 1; +} diff --git a/benchmarks/benchmarks/cfrac/pcmp.c b/benchmarks/benchmarks/cfrac/pcmp.c new file mode 100644 index 0000000..2c8e0b8 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pcmp.c @@ -0,0 +1,68 @@ +#include "pdefs.h" +#include "precision.h" + +/* + * Compare to zero (normalization not assumed) + * + * Returns same as pcmp(u, 0); + */ +int pcmpz(u) + register precision u; +{ + register digitPtr uPtr; + register int i; + + (void) pparm(u); + i = 0; + uPtr = u->value; + do { + if (*uPtr++ != 0) { + if (u->sign) i = -1; else i = 1; + break; + } + } while (uPtr < u->value + u->size); + + pdestroy(u); + return i; +} + +/* + * Compare u to v. + * + * Return: < 0 if u < v + * = 0 if u = v + * > 0 if u > v + * + * This routine is the one that assumes results are normalized! + * - no leading 0's + * - no negative 0 + */ +int pcmp(u, v) + precision u, v; +{ + register digitPtr uPtr, vPtr; + register int i; /* should be bigger than posit */ + + (void) pparm(u); + (void) pparm(v); + if (u->sign != v->sign) { + if (u->sign) i = -1; else i = 1; + } else { + i = u->size - v->size; + if (i == 0) { + uPtr = u->value + u->size; + vPtr = v->value + v->size; + do { + if (*--uPtr != *--vPtr) break; + } while (vPtr > v->value); + if (*uPtr > *vPtr) i = 1; + else if (*uPtr < *vPtr) i = -1; + } + + if (u->sign) i = -i; + } + + pdestroy(u); + pdestroy(v); + return i; +} diff --git a/benchmarks/benchmarks/cfrac/pconst.c b/benchmarks/benchmarks/cfrac/pconst.c new file mode 100644 index 0000000..89b63a7 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pconst.c @@ -0,0 +1,46 @@ +#include "pdefs.h" + +static precisionType pzeroConst = { +#ifndef BWGC + (short) 1, /* refcount (read/write!) */ +#endif + (posit) 1, /* size */ + (posit) 1, /* digitcount */ + (boolean) 0, /* sign */ + { (digit) 0 } /* value */ +}; + +static precisionType poneConst = { +#ifndef BWGC + (short) 1, /* refcount (read/write!) */ +#endif + (posit) 1, /* size */ + (posit) 1, /* digitcount */ + (boolean) 0, /* sign */ + { (digit) 1 } /* value */ +}; + +static precisionType ptwoConst = { +#ifndef BWGC + (short) 1, /* refcount (read/write!) */ +#endif + (posit) 1, /* size */ + (posit) 1, /* digitcount */ + (boolean) 0, /* sign */ + { (digit) 2 } /* value */ +}; + +static precisionType p_oneConst = { +#ifndef BWGC + (short) 1, /* refcount (read/write!) */ +#endif + (posit) 1, /* size */ + (posit) 1, /* digitcount */ + (boolean) 1, /* sign */ + { (digit) 1 } /* value */ +}; + +precision pzero = &pzeroConst; /* zero */ +precision pone = &poneConst; /* one */ +precision ptwo = &ptwoConst; /* two */ +precision p_one = &p_oneConst; /* negative one */ diff --git a/benchmarks/benchmarks/cfrac/pcvt.h b/benchmarks/benchmarks/cfrac/pcvt.h new file mode 100644 index 0000000..e2dd724 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pcvt.h @@ -0,0 +1,32 @@ +/* + * Machine dependent file used for conversion routines + * (e.g. atop, ptoa, itop, ptoi, etc) + */ + +/* + * For pXtop: (X = {i,u,l,ul,d}) + */ +#define INTSIZE 2 /* floor(log[Base](2*(MAXINT+1))) */ +#define LONGSIZE 2 /* floor(log[Base](2*(MAXLONG+1))) */ +#define DOUBLESIZE 129 /* double precision size = log[base](HUGE) */ + +/* + * For ptoX + */ +#define MAXINT (int) ((unsigned int) ~0 >> 1) +#define MAXLONG (long) ((unsigned long) ~0 >> 1) +#define MAXUNSIGNED (~ (unsigned int) 0) +#define MAXUNSIGNEDLONG (~ (unsigned long) 0L) + +#define MAXACC (~ (accumulator) 0) + +/* + * aBase - Ascii base (ptoa) + * There are aDigits Ascii digits per precision digit, pDigits. + * At least one of { aDigits, pDigits } <= (MAXINT / the maximum posit value). + */ +#define aDigits 525 /* aDigits/pDigits >~= log[aBase](Base) */ +#define pDigits 109 /* 525/109=4.8165>log[10](65536)=4.816479931 */ +#define aBase 10 /* string conversion base */ +#define aDigit 1000000000 /* must be power of aBase < MAXINT */ +#define aDigitLog 9 /* log[aBase] of aDigit */ diff --git a/benchmarks/benchmarks/cfrac/pdefs.h b/benchmarks/benchmarks/cfrac/pdefs.h new file mode 100644 index 0000000..9c43099 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pdefs.h @@ -0,0 +1,138 @@ +/* + * +------------------------------------------------------------------+ + * | Private Math Library Definitions | + * +------------------------------------------------------------------+ + */ +/* + * Optional assembly language + */ +#ifdef ASM +#include "machineop.h" /* 16-bit integer machine operations */ +#define uModDiv(n, d, qp) umoddiv16(n, d, qp) /* slight help */ +#else +#define uModDiv(n, d, qp) (*(qp) = (n) / (d), (n) % (d)) +#endif +#define uMul(u, v) ((u) * (v)) /* fast enough */ + +/* + * Optional alternate memory allocator + */ + +#ifndef MYALLOC + +# if defined(BWGC) +extern char *gc_malloc_atomic(); +#define allocate(size) (char *) gc_malloc_atomic(size) +# elif defined(CUSTOM_MALLOC) +#define allocate(size) CUSTOM_MALLOC(size) +# else +/* extern char *malloc(); */ +#define allocate(size) (char *) malloc(size) +# endif + +#ifdef IGNOREFREE +#define deallocate(p) {}; +# elif defined(CUSTOM_FREE) +#define deallocate(p) CUSTOM_FREE(p) +#else +/* +extern int free(); +*/ +#define deallocate(p) free(p) +#endif + +#else +extern char *allocate(); +extern void deallocate(); +#endif + +/* + * These next four types are used only used in this include file + */ +#include +typedef unsigned char u8; /* 8 bits */ +typedef uint16_t u16; /* 16 bits */ +typedef uint32_t u32; /* 32 bits */ +typedef u8 boolean; /* 1 bit */ + +#define BASE 65536 /* Base * (Base-1) <= MAXINT */ + +/* + * Operations on Base (unsigned math) + */ +#define modBase(u) ((u) & 0xffff) /* remainder on Base */ +#define divBase(u) ((u) >> 16) /* divide by Base */ +#define mulBase(u) ((u) << 16) /* multiply by Base */ + +/* + * The type of a variable used to store intermediate results. + * This should be the most efficient unsigned int on your machine. + */ +typedef u32 accumulator; /* 0..(Base * Base) - 1 */ + +/* + * The type of a single digit + */ +typedef u16 digit; /* 0..Base-1 */ + +/* + * The type of a digit index (the largest number of digits - 1) + * Determines the maximum representable precision (not usually changed) + */ +typedef u16 posit; /* 0..size */ + +typedef unsigned short prefc; /* in precision.h also */ +/* + * End of area which needs to be modified + */ + +#define false 0 +#define true 1 + +typedef digit digitString[1]; /* dummy array type */ +typedef digit *digitPtr; + +/* + * A normalized integer has the following attributes: + * -0 cannot occur + * all digits >= size assumed to be 0. (no leading zero's) + * size > 0 + */ +typedef struct { +#ifndef BWGC + prefc refcount; /* reference count (must be 1st [for pref]) */ +#endif + posit alloc; /* allocated size */ + posit size; /* number of digits */ + boolean sign; /* sign: TRUE negative */ + digitString value; +} precisionType; + +typedef precisionType *precision; + +/* + * Overlay for cache of precisions + */ +typedef struct { + precision next; /* next item in list */ + short count; /* number of items in this sublist */ +} cacheType; + +typedef cacheType *cachePtr; +/* + * Maximum total memory consumed by cache = + * LIMIT * (1 + SIZE * (PrecisionSize + sizeof(digit) * (SIZE-1) / 2)) + */ +#ifndef CACHESIZE +#define CACHESIZE 32 /* size of allocation cache */ +#endif +#define CACHELIMIT 128 /* Determines max mem used by cache */ + +#define PrecisionSize (sizeof(precisionType) - sizeof(digitString)) + +/* + * Function definitions are all in the global include file "mathdefs.h". + */ +extern precision palloc(); /* semi-private */ +extern int pfree(); /* semi-private */ +extern void pnorm(); /* semi-private */ diff --git a/benchmarks/benchmarks/cfrac/pdivmod.c b/benchmarks/benchmarks/cfrac/pdivmod.c new file mode 100644 index 0000000..ce4a24b --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pdivmod.c @@ -0,0 +1,315 @@ +#include "pdefs.h" +#include "precision.h" + +#ifdef DEBUG +#include +#endif + +#ifdef ASM_16BIT +#include "asm16bit.h" +#endif + +/* + * Divide u (dividend) by v (divisor); If non-null, qp and rp are set to + * quotient and remainder. The result returned will be *qp, unless qp is + * NULL, then *rp will be returned if non-null, otherwise pUndef is returned. + * + * Produce: + * + * q (quotient) = u div v (v != 0) + * truncation is toward zero + * + * r (remainder) = u mod v + * = u - u div v * v (v != 0) + * = u (v == 0) + * ( e.g. u == q*v + r ) + * remainder has same sign and dividend + * + * Note: this has opposite convention than the C standard div fuction, + * but the same convention of the typical C "/" operator + * It is also inconvienient for the mod function. + */ +/* + * This algorithm is taken almost verbatum from Knuth Vol 2. + * Please note the following trivial(?) array index + * transformations (since MSD to LSD order is reversed): + * + * q[0..m] to Q[0..m] thus q[i] == Q[m-i] + * r[1..n] R[0..n-1] r[i] == R[n+1-i] + * u[0..m+n] w[0..m+n] u[i] == w[m+n-i] + * v[1..n] x[0..n-1] v[i] == x[n-i] + * + * let N == n - 1 so that n == N + 1 thus: + * + * q[0..m] to Q[0..m] thus q[i] == Q[m-i] + * r[1..n] R[0..N] r[i] == R[N+2-i] + * u[0..m+n] w[0..m+N+1] u[i] == w[m+N+1-i] + * v[1..n] x[0..N] v[i] == x[N+1-i] + */ + +/* + * Note: Be very observent of the usage of uPtr, and vPtr. + * They are used to point to u, v, w, q or r as necessary. + */ +precision pdivmod(u, v, qp, rp) + precision u, v, *qp, *rp; +{ + register digitPtr uPtr, vPtr, qPtr, LastPtr; + + register accumulator temp; /* 0 <= temp < base^2 */ + register digit carry; /* 0 <= carry < 2 */ + register digit hi; /* 0 <= hi < base */ + + register posit n, m; + digit d; /* 0 <= d < base */ + digit qd; /* 0 <= qd < base */ +#ifdef DEBUG + int i; +#endif + + precision q, r, w; /* quotient, remainder, temporary */ + + n = v->size; /* size of v and r */ + + (void) pparm(u); + (void) pparm(v); + if (u->size < n) { + q = pUndef; + r = pUndef; + pset(&q, pzero); + pset(&r, u); + goto done; + } + + m = u->size - n; + + uPtr = u->value + m + n; + vPtr = v->value + n; + + q = palloc(m + 1); + if (q == pUndef) return q; + + q->sign = (u->sign != v->sign); /* can generate -0 */ + + r = palloc(n); + if (r == pUndef) { + pdestroy(q); + return r; + } + r->sign = u->sign; +/* + * watch out! does this function return: q=floor(a/b) or trunc(a/b)? + * it's currently the latter, but every mathmaticion I have talked to + * prefers the former so that a % b returns between 0 to b-1. The + * problem is that this is slower and disagrees with C common practice. + */ + qPtr = q->value + m + 1; + + if (n == 1) { + d = *--vPtr; /* d is only digit of v */ + if (d == 0) { /* divide by zero? */ + q = pnew(errorp(PDOMAIN, "pdivmod", "divide by zero")); + } else { /* single digit divide */ +#ifndef ASM_16BIT + vPtr = r->value + n; + hi = 0; /* hi is current remainder */ + do { + temp = mulBase(hi); /* 0 <= temp <= (base-1)^2 */ + temp += *--uPtr; /* 0 <= temp <= base(base-1) */ + hi = uModDiv(temp, d, --qPtr); /* 0 <= hi < base */ + } while (uPtr > u->value); + *--vPtr = hi; +#else + qPtr -= m + 1; + *(r->value) = memdivw1(qPtr, u->value, m + 1, d); +#endif + } + } else { /* muti digit divide */ + /* + * normalize: multiply u and v by d so hi digit of v > b/2 + */ + d = BASE / (*--vPtr+1); /* high digit of v */ + + w = palloc(n); /* size of v */ + if (w == pUndef) return w; + +#ifndef ASM_16BIT + vPtr = v->value; + uPtr = w->value; /* very confusing. just a temp */ + LastPtr = vPtr + n; + hi = 0; + do { /* single digit multiply */ + temp = uMul(*vPtr++, d); /* 0<= temp <= base(base-1)/2 */ + temp += hi; /* 0 <= temp <= (base^2-1)/2 */ + hi = divBase(temp); /* 0 <= hi < base / 2 */ + *uPtr++ = modBase(temp); /* 0 <= hi < base / 2 */ + } while (vPtr < LastPtr); /* on exit hi == 0 */ +#else + hi = memmulw1(w->value, v->value, n, d); +#endif + + pset(&v, w); + pdestroy(w); + + w = palloc(m + n + 1); + if (w == pUndef) return w; + +#ifndef ASM_16BIT + uPtr = u->value; + vPtr = w->value; /* very confusing. just a temp */ + LastPtr = uPtr + m + n; + do { /* single digit multiply */ + temp = uMul(*uPtr++, d); + temp += hi; + hi = divBase(temp); + *vPtr++ = modBase(temp); + } while (uPtr < LastPtr); + *vPtr = hi; /* note extra digit */ +#else + hi = memmulw1(w->value, u->value, m + n, d); + w->value[m + n] = hi; +#endif + + pset(&u, w); + pdestroy(w); + +#ifdef DEBUG + printf("m = %d n = %d\nd = %d\n", m, n, d); + printf("norm u = "); pshow(u); + printf("norm v = "); pshow(v); +#endif + + uPtr = u->value + m + 1; /* current least significant digit */ + do { + --uPtr; +#ifdef DEBUG + printf(" u = "); + for (i = n; i >= 0; --i) printf("%.*x ", sizeof(digit) * 2, uPtr[i]); + putchar('\n'); + printf(" v = "); + for (i = 1; i < 3; i++) printf("%.*x ", sizeof(digit) * 2, + v->value[n-i]); + putchar('\n'); +#endif +#ifndef ASM_16BIT + vPtr = v->value + n; + LastPtr = uPtr + n; + if (*LastPtr == *--vPtr) { /* guess next digit */ + qd = BASE - 1; + } else { + temp = mulBase(*LastPtr); + temp += *--LastPtr; /* 0 <= temp< base^2 */ + temp = uModDiv(temp, *vPtr, &qd); + --vPtr; + --LastPtr; + while (uMul(*vPtr, qd) > mulBase(temp) + *LastPtr) { + --qd; + temp += vPtr[1]; + if (temp >= BASE) break; /* if so, vPtr*qd <= temp*base */ + } + LastPtr += 2; + } + /* + * Single digit Multiply then Subtract + */ + vPtr = v->value; + carry = 1; /* noborrow bit */ + hi = 0; /* hi digit of multiply */ + do { + /* multiply */ + temp = uMul(qd, *vPtr++); /* 0 <= temp <= (base-1)^2 */ + temp += hi; /* 0 <= temp <= base(base-1) */ + hi = divBase(temp); + temp = modBase(temp); + /* subtract */ + temp = (BASE-1) - temp; /* 0 <= temp < base */ + temp += *uPtr + carry; /* 0 <= temp < 2*base */ + carry = divBase(temp); + *uPtr++ = modBase(temp); /* 0 <= carry < 2 */ + } while (uPtr < LastPtr); + temp = (BASE-1) - hi; + temp += *uPtr + carry; + carry = divBase(temp); + *uPtr = modBase(temp); + uPtr -= n; +#else +#if 0 + carry = !memmulsubw(uPtr, v->value, n, qd); /* 1 if noborrow */ +#endif + carry = !memdivw(uPtr, v->value, n, &qd); /* 1 if noborrow */ +#endif +#ifdef DEBUG + printf(" qhat = %.*x\n", sizeof(digit) * 2, qd); + printf(" new u = "); + for (i = n; i >= 0; --i) printf("%.*x ", sizeof(digit) * 2, uPtr[i]); + putchar('\n'); +#endif + if (carry == 0) { /* Test remainder, add back */ + vPtr = v->value; + LastPtr = uPtr + n; + do { + temp = *uPtr + *vPtr++; + temp += carry; + carry = divBase(temp); + *uPtr++ = modBase(temp); + } while (uPtr < LastPtr); + *uPtr += carry - BASE; /* real strange but works */ + uPtr -= n; + --qd; +#ifdef DEBUG + printf(" decrementing q...adding back\n"); + printf(" fixed u = "); + for (i = n; i >= 0; --i) printf("%.*x ", sizeof(digit) * 2, uPtr[i]); + putchar('\n'); + printf(" newq = %.*x\n", sizeof(digit) * 2, qd); +#endif + } + *--qPtr = qd; /* one leading zero possible */ +#ifdef DEBUG + putchar('\n'); +#endif + } while (uPtr > u->value); + + /* + * Un-normalize to get remainder + */ +#ifndef ASM_16BIT + uPtr = u->value + n; /* skip hi digit (it's zero) */ + vPtr = r->value + n; + hi = 0; /* hi is current remainder */ + do { /* single digit divide */ + temp = mulBase(hi); /* 0<=temp < base^2-(base-1) */ + temp += *--uPtr; /* 0 <= temp < base^2 */ + hi = uModDiv(temp, d, --vPtr); + } while (uPtr > u->value); /* carry will be zero */ +#else + carry = memdivw1(r->value, u->value, n, d); /* always 0 */ +#endif + pnorm(r); /* remainder may have many leading 0's */ + } + + if (m > 0 && qPtr[m] == 0) { + --(q->size); /* normalize */ + } + if (q->size == 1 && *qPtr == 0) q->sign = false; + +done: + + pdestroy(u); + pdestroy(v); + + if (rp == (precision *) -1) { + if (qp != pNull) pset(qp, q); + pdestroy(q); + return presult(r); + } else if (qp == (precision *) -1) { + if (rp != pNull) pset(rp, r); + pdestroy(r); + return presult(q); + } + if (qp != pNull) pset(qp, q); + if (rp != pNull) pset(rp, r); + pdestroy(q); + pdestroy(r); + return pUndef; +} diff --git a/benchmarks/benchmarks/cfrac/pfactor.c b/benchmarks/benchmarks/cfrac/pfactor.c new file mode 100644 index 0000000..6c765d1 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pfactor.c @@ -0,0 +1,55 @@ +#include +#include "precision.h" +#include "pfactor.h" + +void showfactors(); + + +int main(argc, argv) + int argc; + char *argv[]; +{ + precision n = pUndef; + + --argc; + if (argc != 0) { + do { + pset(&n, atop(*++argv)); + showfactors(n); + } while (--argc > 0); + } else { + do { + pset(&n, fgetp(stdin)); + if (n == pUndef) break; + showfactors(n); + } while (1); + } + pdestroy(n); + return 0; +} + +void showfactors(n) + precision n; +{ + precision r = pUndef; + FactorList factors = (FactorList) 0; + + (void) pparm(n); + pset(&r, ptrial(n, (unsigned *) 0, &factors)); + fputp(stdout, n); + fputs(" = ", stdout); + pputfactors(stdout, factors); + if pne(r, pone) { + if pne(r, n) putc('*', stdout); + if (!pprime(r, 16)) { + fputc('(', stdout); fputp(stdout, r); fputc(')', stdout); + } else { + fputp(stdout, r); + } + } + putc('\n', stdout); + + pfreefactors(&factors); + pdestroy(r); + pdestroy(n); +} diff --git a/benchmarks/benchmarks/cfrac/pfactor.h b/benchmarks/benchmarks/cfrac/pfactor.h new file mode 100644 index 0000000..edd5686 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pfactor.h @@ -0,0 +1,62 @@ +typedef struct Pfs { + struct Pfs *next; + precision factor; + unsigned count; +} Pfactor; + +typedef Pfactor *FactorPtr; +typedef FactorPtr FactorList; +typedef precision (*pfunc)(); /* pointer to func returning precision */ + +#ifndef __STDC__ + +extern int pprime(); /* test whether a number is prime */ +extern precision pnextprime(); /* next prime >= it's argument */ + +extern precision pgcd(); /* greatest common divisor */ +extern precision plcm(); /* least common multiple */ +extern precision peuclid(); /* extended euclid's algorithm */ + +extern precision prho(); /* find factor using rho method */ +extern precision pfermat(); /* find factor using Fermat's method */ +extern precision pcfrac(); /* factor w/continued fractions */ + +extern int prhoInit(); /* alter parameters for rho method */ +extern int pcfracInit(); /* alter paramteres for cfrac method */ + +extern precision ptrial(); /* find factors using trial division */ +extern precision prfactor(); /* recursively factor a number */ + +extern void paddfactor(); /* add a factor to a factorlist */ +extern void pputfactors(); /* print a factorlist */ +extern void pfreefactors(); /* return a factorlist to memory */ + +#else + +extern int pprime(precision, unsigned trialCount); +extern precision pnextprime(precision, unsigned trialCount); + +extern precision pgcd(precision, precision); +extern precision plcm(precision, precision); +extern precision peuclid(precision, precision, precision *, precision *); + +extern precision prho(precision n, unsigned *maxCount); +extern precision pfermat(precision n, unsigned *maxCount); +extern precision pcfrac(precision n, unsigned *maxCount); + +extern int prhoInit(precision c, unsigned batchSize); +extern int pcfracInit(unsigned m, unsigned k, unsigned aborts); + +extern precision ptrial(precision n, unsigned *maxCount, FactorList *); +extern precision prfactor(precision, unsigned *maxCount, pfunc, FactorList *); + +extern void paddfactor(FactorList *, precision); +extern void pfreefactors(FactorList *); + +#ifndef BUFSIZE +#include +#endif + +extern void pputfactors(FILE *, FactorList); + +#endif diff --git a/benchmarks/benchmarks/cfrac/pfloat.c b/benchmarks/benchmarks/cfrac/pfloat.c new file mode 100644 index 0000000..63f4344 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pfloat.c @@ -0,0 +1,61 @@ +/* + * High Precision Math Library Supplement for floating point routines + */ +#include +#include +#include "pdefs.h" +#include "pcvt.h" +#include "precision.h" + +extern precision palloc(); + +/* + * double to precision + */ +precision dtop(f) + register double f; +{ + register digitPtr uPtr; + register precision u; + + u = palloc(DOUBLESIZE); /* pretty big */ + if (u == pUndef) return u; + + if (f < 0.0) { + f = -f; + u->sign = true; + } else { + u->sign = false; + } + uPtr = u->value; + do { + *uPtr++ = fmod(f, (double) BASE); + f = floor(f / (double) BASE); + } while (f != 0.0); + + u->size = (uPtr - u->value); + + return presult(u); +} + +/* + * precision to double (no overflow check) + */ +double ptod(u) + precision u; +{ + register digitPtr uPtr; + register double f; + + (void) pparm(u); + uPtr = u->value + u->size; + f = 0.0; + do { + f = f * (double) BASE + (double) *--uPtr; + } while (uPtr > u->value); + + if (u->sign) f = -f; + + pdestroy(u); + return f; +} diff --git a/benchmarks/benchmarks/cfrac/pgcd.c b/benchmarks/benchmarks/cfrac/pgcd.c new file mode 100644 index 0000000..a72a8a7 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pgcd.c @@ -0,0 +1,24 @@ +#include "precision.h" + +/* + * Euclid's Algorithm + * + * Given u and v, calculated and return their greatest common divisor. + */ +precision pgcd(u, v) + precision u, v; +{ + precision u3 = pnew(pabs(pparm(u))), v3 = pnew(pabs(pparm(v))); + precision q = pUndef, r = pUndef; + + while (pnez(v3)) { + pdivmod(u3, v3, &q, &r); + pset(&u3, v3); + pset(&v3, r); + } + + pdestroy(v3); + pdestroy(q); pdestroy(r); + pdestroy(u); pdestroy(v); + return presult(u3); /* result always positive */ +} diff --git a/benchmarks/benchmarks/cfrac/phalf.c b/benchmarks/benchmarks/cfrac/phalf.c new file mode 100644 index 0000000..8658de5 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/phalf.c @@ -0,0 +1,36 @@ +#include +#include "pdefs.h" +#include "precision.h" + +#ifdef ASM_16BIT +#include "asm16bit.h" +#endif + +/* + * Divide a precision by 2 + */ +precision phalf(u) + register precision u; +{ +#ifdef ASM_16BIT + register precision w; + register posit usize; + + pparm(u); + usize = u->size; + w = palloc(usize); + if (w == pUndef) return w; + + w->sign = u->sign; + (void) memcpy(w->value, u->value, usize * sizeof(digit)); + + memlsrw(w->value, usize); /* 68000 assembly language routine */ + if (usize > 1 && w->value[usize-1] == (digit) 0) { /* normalize */ + --(w->size); + } + pdestroy(u); + return presult(w); +#else + return pdiv(u, ptwo); +#endif +} diff --git a/benchmarks/benchmarks/cfrac/picmp.c b/benchmarks/benchmarks/cfrac/picmp.c new file mode 100644 index 0000000..b942268 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/picmp.c @@ -0,0 +1,41 @@ +#include "pdefs.h" +#include "precision.h" + +static char cmpError[] = "Second arg not single digit"; + +/* + * Single-digit compare + */ +int picmp(u, v) + register precision u; + register int v; +{ + register int i; + + (void) pparm(u); + + if (u->sign) { + i = -1; + if (v < 0) { + if (-v >= BASE) { + errorp(PDOMAIN, "picmp", cmpError); + } + if (u->size == 1) { + i = - (int) *(u->value) - v; + } + } + } else { + i = 1; + if (v >= 0) { + if (v >= BASE) { + errorp(PDOMAIN, "picmp", cmpError); + } + if (u->size == 1) { + i = (int) *(u->value) - v; + } + } + } + + pdestroy(u); + return i; +} diff --git a/benchmarks/benchmarks/cfrac/pidiv.c b/benchmarks/benchmarks/cfrac/pidiv.c new file mode 100644 index 0000000..61c09a7 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pidiv.c @@ -0,0 +1,60 @@ +#include "pdefs.h" +#include "precision.h" +#ifdef ASM_16BIT +#include "asm16bit.h" +#endif + +/* + * Single-digit divide + */ +precision pidiv(u, v) + register precision u; + int v; +{ +#ifndef ASM_16BIT + register digitPtr uPtr, qPtr; + register accumulator temp; /* 0 <= temp < base^2 */ +#endif + register digit r, d; /* 0 <= r,d < base */ + register posit m; + register precision q; + + (void) pparm(u); + + if (v < 0) d = (digit) -v; else d = (digit) v; + if (d >= BASE) { + q = pnew(errorp(PDOMAIN, "pidiv", "divisor too big for single digit")); + goto done; + } + if (d == 0) { + q = pnew(errorp(PDOMAIN, "pidiv", "divide by zero")); + goto done; + } + m = u->size; + q = palloc(m); + if (q == pUndef) goto done; + +#ifndef ASM_16BIT + qPtr = q->value + m; + uPtr = u->value + m; + r = 0; /* r is current remainder */ + do { + temp = mulBase(r); /* 0 <= temp <= (base-1)^2 */ + temp += *--uPtr; /* 0 <= temp <= base(base-1) */ + r = uModDiv(temp, d, --qPtr); /* 0 <= r < base */ + } while (uPtr > u->value); +#else + r = memdivw1(q->value, u->value, m, d); +#endif + /* + * normalize q + */ + if (m > 1 && q->value[m-1] == 0) { + --(q->size); + } + q->sign = (u->sign != (v < 0)); + if (q->size == 1 && *(q->value) == 0) q->sign = false; +done: + pdestroy(u); + return presult(q); +} diff --git a/benchmarks/benchmarks/cfrac/pimod.c b/benchmarks/benchmarks/cfrac/pimod.c new file mode 100644 index 0000000..b26536d --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pimod.c @@ -0,0 +1,48 @@ +#include "pdefs.h" +#include "precision.h" +#ifdef ASM_16BIT +#include "asm16bit.h" +#endif + +/* + * Single-digit remainder + */ +int pimod(u, v) + register precision u; + int v; +{ +#ifndef ASM_16BIT + register digitPtr uPtr; + register accumulator temp; /* 0 <= temp < base^2 */ +#endif + register digit r = 0, d; /* 0 <= r,d < base */ + register int res = 0; + + (void) pparm(u); + if (v < 0) d = (digit) -v; else d = (digit) v; + if (d >= BASE) { + errorp(PDOMAIN, "pimod", "divisor too big for single digit"); + goto done; + } + if (d == 0) { + errorp(PDOMAIN, "pimod", "divide by zero"); + goto done; + } +#ifndef ASM_16BIT + uPtr = u->value + u->size; + r = 0; /* r is current remainder */ + do { + temp = mulBase(r); /* 0 <= temp <= (base-1)^2 */ + temp += *--uPtr; /* 0 <= temp <= base(base-1) */ + r = temp % d; /* 0 <= r < base */ + } while (uPtr > u->value); +#else + r = memmodw1(u->value, u->size, d); +#endif + + res = (int) r; + if (u->sign) res = -res; +done: + pdestroy(u); + return res; +} diff --git a/benchmarks/benchmarks/cfrac/pio.c b/benchmarks/benchmarks/cfrac/pio.c new file mode 100644 index 0000000..16b5bda --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pio.c @@ -0,0 +1,165 @@ +#include +#include +#include +#include "pdefs.h" +#include "pcvt.h" +#include "precision.h" + +/* + * Output a string to a file. + * + * Returns: + * the number of characters written + * or EOF if error + */ +static int fouts(stream, chp) + FILE *stream; + register char *chp; +{ + register int count = 0, res = 0; + + if (chp != (char *) 0 && *chp != '\0') do { + count++; + res = putc(*chp, stream); + } while (*++chp != '\0' && res != EOF); + + if (res != EOF) res = count; + return res; +} + +/* + * output the value of a precision to a file (no cr or whitespace) + * + * Returns: + * The number of characters output or EOF if error + */ +int fputp(stream, p) + FILE *stream; + precision p; +{ + int res; + char *chp = ptoa(pparm(p)); + + res = fouts(stream, chp); + deallocate(chp); + pdestroy(p); + return res; +} + +/* + * Output a precision to stdout with a newline (useful from debugger) + */ +int putp(p) + precision p; +{ + int res; + char *chp = ptoa(pparm(p)); + + res = fouts(stdout, chp); + res = putc('\n', stdout); + deallocate(chp); + pdestroy(p); + return res; + +} + +/* + * Output a justified precision + * + * Returns: The number of characters in the precision, or EOF if error + */ +int fprintp(stream, p, minWidth) + FILE *stream; + precision p; + register int minWidth; +{ + int res; + char *chp = ptoa(pparm(p)); + int len; + + len = strlen(chp); + if (minWidth < 0) { /* left-justified */ + res = fouts(stream, chp); + while (minWidth++ < -len) { + putc(' ', stream); + } + } else { + while (minWidth-- > len) { /* right-justified */ + putc(' ', stream); + } + res = fouts(stream, chp); + } + + deallocate(chp); + pdestroy(p); + return res; +} + + +/* + * Read in a precision type - same as atop but with io + * + * leading whitespace skipped + * an optional leading '-' or '+' followed by digits '0'..'9' + * leading 0's Ok + * stops at first unrecognized character + * + * Returns: pUndef if EOF or invalid argument (NULL or nondigit as 1st digit) + */ +precision fgetp(stream) + FILE *stream; +{ + precision res = pUndef; + precision clump = pUndef; + int sign = 0; + register int ch; + register accumulator temp, x; + register int j; + + ch = getc(stream); + if (ch != EOF) { + while (isspace(ch)) ch = getc(stream); /* skip whitespace */ + if (ch == '-') { + sign = 1; + ch = getc(stream); + } else if (ch == '+') { + ch = getc(stream); + } + if (isdigit(ch)) { + pset(&res, pzero); + pset(&clump, utop(aDigit)); + do { + j = aDigitLog-1; + temp = ch - '0'; + do { + if (!isdigit(ch = getc(stream))) goto atoplast; + temp = temp * aBase + (ch - '0'); + } while (--j > 0); + pset(&res, padd(pmul(res, clump), utop(temp))); + } while (isdigit(ch = getc(stream))); + goto atopdone; +atoplast: + x = aBase; + while (j++ < aDigitLog-1) { + x *= aBase; + } + pset(&res, padd(pmul(res, utop(x)), utop(temp))); +atopdone: + if (ch != EOF) ungetc(ch, stream); + if (sign) { + pset(&res, pneg(res)); + } + } else { + if (ch == EOF) { + res = pUndef; + } else { + ungetc(ch, stream); + } + } + } else { + res = pUndef; + } + pdestroy(clump); + if (res == pUndef) return res; + return presult(res); +} diff --git a/benchmarks/benchmarks/cfrac/pmul.c b/benchmarks/benchmarks/cfrac/pmul.c new file mode 100644 index 0000000..e69a366 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pmul.c @@ -0,0 +1,84 @@ +#include "pdefs.h" +#include "precision.h" +#include + +#ifdef ASM_16BIT +#include "asm16bit.h" +#endif + +/* + * Multiply u by v (assumes normalized) + */ +precision pmul(u, v) + register precision v; /* register a5 on 68000 */ +#ifdef ASM_16BIT + register precision u; /* register a4 */ +{ +#else + precision u; +{ + digitPtr vPtr; + register digitPtr uPtr, wPtr, HiDigit; + register accumulator temp; /* 0 <= temp < base * base */ /* d7 */ + register digit vdigit; /* d6 */ +#endif + register digit hi; /* 0 <= hi < base */ /* d5 */ + precision w; + + (void) pparm(u); + (void) pparm(v); + /* + * Check for multiply by zero. Helps prevent wasted storage and -0 + */ + if (peqz(u) || peqz(v)) { + w = palloc(1); + if (w == pUndef) return w; + + w->sign = false; + w->value[0] = 0; + } else { + if (u->size < v->size) { /* u is biggest number (for inner loop speed) */ + w = u; u = v; v = w; + } + + w = palloc(u->size + v->size); + if (w == pUndef) return w; + + w->sign = (u->sign != v->sign); + +#ifndef ASM_16BIT + uPtr = u->value; + vPtr = v->value; + wPtr = w->value + u->size; /* this is correct! */ + do { + *--wPtr = 0; + } while (wPtr > w->value); + + vPtr = v->value; + HiDigit = u->value + u->size; + do { + uPtr = u->value; + wPtr = w->value + (vPtr - v->value); + hi = 0; + vdigit = *vPtr; + do { + temp = uMul(vdigit, *uPtr++); /* 0 <= temp <= (base-1)^2 */ + temp += *wPtr; /* 0 <= temp <= base(base-1) */ + temp += hi; /* 0 <= temp < base * base */ + hi = divBase(temp); /* 0 <= hi < base */ + *wPtr++ = modBase(temp); + } while (uPtr < HiDigit); + *wPtr++ = hi; + } while (++vPtr < v->value + v->size); +#else + hi = memmulw(w->value, u->value, u->size, v->value, v->size); +#endif + if (hi == 0) { + --(w->size); /* normalize */ + } + } + + pdestroy(u); + pdestroy(v); + return presult(w); +} diff --git a/benchmarks/benchmarks/cfrac/pneg.c b/benchmarks/benchmarks/cfrac/pneg.c new file mode 100644 index 0000000..c781066 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pneg.c @@ -0,0 +1,25 @@ +#include "pdefs.h" /* private include file */ +#include "precision.h" /* public include file for forward refs */ +#include + +/* + * negation + */ +precision pneg(u) + register precision u; +{ + precision w; + + (void) pparm(u); + w = palloc(u->size); + if (w == pUndef) return w; + + w->sign = u->sign; + if (pnez(u)) { /* don't create a negative 0 */ + w->sign = !w->sign; + } + (void) memcpy(w->value, u->value, u->size * sizeof(digit)); + + pdestroy(u); + return presult(w); +} diff --git a/benchmarks/benchmarks/cfrac/podd.c b/benchmarks/benchmarks/cfrac/podd.c new file mode 100644 index 0000000..def95b4 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/podd.c @@ -0,0 +1,16 @@ +#include "pdefs.h" +#include "precision.h" + +/* + * Returns non-zero if u is odd + */ +int podd(u) + precision u; +{ + register int res; + + (void) pparm(u); + res = (*(u->value) & 1); + pdestroy(u); + return res; +} diff --git a/benchmarks/benchmarks/cfrac/pops.c b/benchmarks/benchmarks/cfrac/pops.c new file mode 100644 index 0000000..7154dd7 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/pops.c @@ -0,0 +1,339 @@ +#ifdef DEBUGOPS +#include +#endif +/* + * High Precision Math Library + * + * Written by Dave Barrett 2/23/83 + * Translated from modcal to pascal 4/30/84 + * Mod portability fixed; removed floor function 5/14/84 + * Fixed numerous bugs and improved robustness 5/21/84 + * Translated to C 6/14/84 + * Changed precision to be determined at run-time 5/19/85 + * Added dynamic allocation 7/21/85 + * Combined unsigned math and integer math 8/01/85 + * Fixed Bug in pcmp 7/20/87 + * Fixed handling of dynamic storage (refcount added) 7/20/87 + * Final debugging of current version 8/22/87 + * Fixed many bugs in various routines, wrote atop 2/07/89 + * Tuned for speed, fixed overflow problems 3/01/89 + * Removed refcounts, more tuning, removed pcreate 3/16/89 + * Added cmp macros, change name of pzero, added pshift 4/29/89 + * Repaired operation order bugs in pdiv, calc.c 5/15/91 + * Added pdiv macro, split out pcmp, pabs, much cleanup 5/21/91 + * + * warning! The mod operation with negative arguments not portable. + * I have therefore avoided it completely with much pain. + * + * The following identities have proven useful: + * + * given: a % b = a - floor(a/b) * b + * then : -a % -b = -(a % b) + * -a % b = -( a % -b) = b - a % b (a % b != 0) + * a % -b = -(-a % b) = a % b - b (a % b != 0) + * + * given: a % b = a - a / b * b + * then : -a % -b = -a % b = -(a % b) + * a % -b = a % b + * + * Also, be very careful of computations in the inner loops. Much + * work has been done to make sure the compiler does not re-arrange + * expressions to cause an overflow. The compiler may still be doing + * unnecessary type conversions. + * + * NOTES: + * + * The ptoa routine creates storage which is likely to be forgotton. + * + * A function returning a result must use the result. If it doesn't + * the storage is never freed. For example: itop(2); by itself + * You must make sure to pdestroy the result. + * + * An error (out of storage) fails to deallocate u and v. + * + * psub, pcmp, pdiv, and pmul all assume normalized arguments. + * + * This file contains the storage management-specific code: + * palloc, pfree, pset -- together these account for 45% of execution time + */ +#include +#include "pdefs.h" /* private include file */ +#include "precision.h" /* public include file for forward refs */ + +cacheType pcache[CACHESIZE]; +static char ident[] = + " @(#) libprecision.a version 2.00 3-May-91 by Dave Barrett\n"; + +/* + * normalize (used by div and sub) + * remove all leading zero's + * force positive sign if result is zero + */ +void pnorm(u) + register precision u; +{ + register digitPtr uPtr; + + uPtr = u->value + u->size; + do { + if (*--uPtr != 0) break; + } while (uPtr > u->value); + + if (uPtr == u->value && *uPtr == 0) u->sign = false; + + u->size = (uPtr - u->value) + 1; /* normalize */ +} + +/* + * Create a number with the given size (private) (very heavily used) + */ +precision palloc(size) + register posit size; +{ + register precision w; + register cacheType *kludge = pcache + size; /* for shitty compilers */ + +#if !(defined(NOMEMOPT) || defined(BWGC)) + if (size < CACHESIZE && (w = kludge->next) != pUndef) { + kludge->next = ((cacheType *) w)->next; + --kludge->count; + } else { +#endif + w = (precision) allocate(PrecisionSize + sizeof(digit) * size); + if (w == pUndef) { + w = errorp(PNOMEM, "palloc", "out of memory"); + return w; + } +#if !(defined(NOMEMOPT) || defined(BWGC)) + } +#endif +#ifndef BWGC + w->refcount = 1; +#endif + w->size = w->alloc = size; +#ifdef DEBUGOPS + printf("alloc %.8x\n", w); + fflush(stdout); +#endif + return w; +} + +/* + * (Very heavily used: Called conditionally pdestroy) + * (should be void, but some compilers can't handle it with the macro) + */ +int pfree(u) + register precision u; +{ + register posit size; + register cacheType *kludge; /* for shitty compilers */ + +#ifdef DEBUGOPS + printf("free %.8x\n", u); + fflush(stdout); +#endif + + size = u->alloc; + + kludge = pcache + size; +#if !(defined(NOMEMOPT) || defined(BWGC)) + if (size < CACHESIZE && kludge->count < CACHELIMIT) { + ((cacheType *) u)->next = kludge->next; + kludge->next = u; + kludge->count++; + } else { +#endif + deallocate(u); +#if !(defined(NOMEMOPT) || defined(BWGC)) + } +#endif + return 0; +} + +/* + * User inteface: + * + * Rules: + * a precision must be initialized to pUndef or to result of pnew. + * a precision pointer must point to a precision or be pNull + * pUndef may not be passed as an rvalue into a function + * pNull may not be passed as an lvalue into a function + * + * presult and pdestroy are the only functions which may be passed pUndef + */ + +/* + * assignment with verification (slower, but helpful for bug detect) + * It would be nice if this routine could detect pointers to incorrect + * or non-living areas of memory. + * + * We can't check for undefined rvalue because we want to allow functions + * to return pUndef, and then let the application check for it after assigning + * it to a variable. + * + * usage: pset(&i, j); + */ +precision psetv(up, v) + register precision *up, v; +{ + register precision u; + +#ifdef DEBUGOPS + printf("psetv %.8x %.8x ", up, v); +#endif +#ifdef DEBUGOPS +#ifndef BWGC + printf("->%u", v->refcount); +#endif +#endif + if (up == pNull) { + errorp(PDOMAIN, "pset", "lvalue is pNull"); + } + u = *up; +#ifdef DEBUGOPS + printf(" %.8x", u); +#endif + *up = v; + if (v != pUndef) { +#ifndef BWGC + v->refcount++; +#endif + } + if (u != pUndef) { + if (u->sign & ~1) { /* a minimal check */ + errorp(PDOMAIN, "pset", "invalid precision"); + } +#ifndef BWGC + if (--(u->refcount) == 0) { +#ifdef DEBUGOPS + printf("->%u", u->refcount); +#endif + pfree(u); + } +#endif + } +#ifdef DEBUGOPS + putchar('\n'); + fflush(stdout); +#endif + return v; +} + +precision pparmv(u) + register precision u; +{ +#ifdef DEBUGOPS + printf("pparm %.8x\n", u); + fflush(stdout); +#endif + if (u == pUndef) { + errorp(PDOMAIN, "pparm", "undefined function argument"); + } + if (u->sign & ~1) { /* a minimal check */ + errorp(PDOMAIN, "pparm", "invalid precision"); + } +#ifndef BWGC + u->refcount++; +#endif + return u; +} + +/* + * Function version of unsafe pparmq macro + */ +precision pparmf(u) + register precision u; +{ +#ifndef BWGC + if (u != pUndef) { + u->refcount++; + } +#endif + return u; +} + +/* + * Function version of pdestroy macro + */ +void pdestroyf(u) + register precision u; +{ +#ifndef BWGC + if (u != pUndef && --u->refcount == 0) { + pfree(u); + } +#endif +} + +#ifndef __GNUC__ /* inline in header file */ +/* + * We cannot allow this to be a macro because of the probability that it's + * argument will be a function (e.g. utop(2)) + */ +precision pnew(u) + register precision u; +{ +#ifndef BWGC + u->refcount++; +#endif + return u; +} + +/* + * Cannot be a macro because of function argument possibility + */ +precision presult(u) + register precision u; +{ +#ifndef BWGC + if (u != pUndef) { + --(u->refcount); + } +#endif + return u; +} + +/* + * Quick but dangerous assignment + * + * Assumes: target not pNull and source not pUndef + */ +precision psetq(up, v) + register precision *up, v; +{ + register precision u = *up; /* up may NOT be pNULL! */ + + *up = v; /* up may be &v, OK */ +#ifndef BWGC + if (v != pUndef) { /* to allow: x=func(); if (x==pUndef) ... */ + v->refcount++; + } + if (u != pUndef && --(u->refcount) == 0) { + pfree(u); + } +#endif + return v; +} +#endif + +#if 0 /* original assignment code */ +precision pset(up, v) + register precision *up, v; +{ + register precision u; + +#ifndef BWGC + if (v != pUndef) v->refcount++; +#endif + if (up == pNull) { /* useful voiding parameters (pdiv) */ + pdestroy(v); + return pUndef; + } + u = *up; + if (u != pUndef) { /* useful to force initial creation */ + pdestroy(u); + } + *up = v; /* notice that v may be pUndef which is OK! */ + return v; /* no presult! This is a variable */ +} +#endif diff --git a/benchmarks/benchmarks/cfrac/ppowmod.c b/benchmarks/benchmarks/cfrac/ppowmod.c new file mode 100644 index 0000000..4528db9 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/ppowmod.c @@ -0,0 +1,28 @@ +#include "precision.h" + +/* + * Raise to precision power mod m + */ +precision ppowmod(u, v, m) + precision u, v, m; +{ + precision j = pUndef, i = pUndef, n = pUndef; + + (void) pparm(m); + pset(&i, pparm(u)); + pset(&n, pparm(v)); + pset(&j, pone); + + do { + if (podd(n)) { + pset(&j, pmod(pmul(i, j), m)); + } + pset(&n, phalf(n)); + if (peqz(n)) break; + pset(&i, pmod(pmul(i, i), m)); + } while (1); + + pdestroy(i); pdestroy(n); + pdestroy(u); pdestroy(v); pdestroy(m); + return presult(j); +} diff --git a/benchmarks/benchmarks/cfrac/precision.h b/benchmarks/benchmarks/cfrac/precision.h new file mode 100644 index 0000000..28befce --- /dev/null +++ b/benchmarks/benchmarks/cfrac/precision.h @@ -0,0 +1,314 @@ +/* + * Arbitrary precision integer math package + * + * (c) Copyright 1991 by David A. Barrett (barrett@asgard.UUCP) + * + * Not to be used for profit or distributed in systems sold for profit + */ + + +/* BEGIN EDB */ + +#include + +#if defined(USE_LOCH) && defined(_WIN32) +#pragma comment(lib, "loch.lib") +#endif + +#define NOMEMOPT 1 + +/* END EDB */ + +#ifndef BASE +typedef unsigned short prefc; /* reference counter type */ +typedef prefc *precision; /* this a a private data structure */ +extern int pfree(); /* free (private) */ +#endif + +typedef precision *pvector; /* a vector of precision */ +typedef pvector *parray; /* 2d array */ + +/* + * Error values passed to errorp + */ +#define PNOERROR 0 +#define PNOMEM 1 +#define PREFCOUNT 2 +#define PUNDEFINED 3 +#define PDOMAIN 4 +#define POVERFLOW 5 + +#define pUndef ((precision) 0) /* An undefined value */ +#define pNull ((precision *) 0) + +#define peq(u, v) (pcmp((u), (v)) == 0) +#define pne(u, v) (pcmp((u), (v)) != 0) +#define pgt(u, v) (pcmp((u), (v)) > 0) +#define plt(u, v) (pcmp((u), (v)) < 0) +#define pge(u, v) (pcmp((u), (v)) >= 0) +#define ple(u, v) (pcmp((u), (v)) <= 0) + +#define peqz(u) (pcmpz(u) == 0) +#define pnez(u) (pcmpz(u) != 0) +#define pltz(u) (pcmpz(u) < 0) +#define pgtz(u) (pcmpz(u) > 0) +#define plez(u) (pcmpz(u) <= 0) +#define pgez(u) (pcmpz(u) >= 0) + +#define peven(u) (!podd(u)) +#define pdiv(u,v) (pdivmod(u,v, (precision *) -1, pNull)) +#define pmod(u,v) (pdivmod(u,v, pNull, (precision *) -1)) +#define pdivr(u,v,r) (pdivmod(u,v, (precision *) -1, r)) +#define pmodq(u,v,q) (pdivmod(u,v, q, (precision *) -1)) + +/* + * Application programs should only use the following definitions; + * + * pnew, pdestroy, pparm, presult and pset + * + * Other variants are internal only! + * All are side-effect safe except for pparm and presult. + * -DDEBUG will enable argument checking for pset and pparm + */ +#ifdef __GNUC__ /* inline is NOT ansii! Sigh. */ +#ifndef BWGC +static inline precision pnew(precision u) { (* (prefc *) u)++; return u; } +static inline void pdestroy(precision u) { + if (u != pUndef && --(*(prefc *) u) == 0) pfree(u); +} +static inline precision pparmq(precision u) { + if (u != pUndef) (* (prefc *) u)++; return u; +} +static inline precision presult(precision u) { + if (u != pUndef) --(*(prefc *) u); return u; +} +static inline precision psetq(precision *up, precision v) { + precision u = *up; + *up = v; + if (v != pUndef) (* (prefc *) v)++; + if (u != pUndef && --(* (prefc *) u) == 0) pfree(u); + return v; +} +#define pvoid(u) pdestroy(u) +#else +extern inline precision pnew(precision u) { return u; } +extern inline void pdestroy(precision u) {} +extern inline precision pparmq(precision u) { return u; } +extern inline precision presult(precision u) { return u; } +extern inline precision psetq(precision *up, precision v) { + precision u = *up; + *up = v; + return v; +} +#define pvoid(u) pdestroy(u) +#endif +#else +#ifndef BWGC +#define pdestroy(u) (void) ((u)!=pUndef&&--(*(prefc *)(u))==0&&pfree(u)) +#define pparmq(u) ((u) != pUndef && (* (prefc *) (u))++, (u)) +#define pvoid(u) pdestroyf(u) +#else +#define pdestroy(u) (void) (0) +#define pparmq(u) (u) +#define pvoid(u) pdestroyf(u) +#endif +#endif + + +#ifdef PDEBUG +#define pset(u, v) psetv(u, v) +#define pparm(u) pparmv(u) +#else +#define pset(u, v) psetq(u, v) +#define pparm(u) pparmq(u) +#endif + +#ifdef __STDC__ /* if ANSI compiler */ +#ifndef __GNUC__ +extern precision pnew(precision); /* initialization */ +extern precision presult(precision); /* function result */ +extern precision psetq(precision *, precision); /* quick assignment */ +#endif +extern precision psetv(precision *, precision); /* checked assignment */ +extern precision pparmv(precision); /* checked parameter */ +extern precision pparmf(precision); /* unchecked parameter (fn) */ + +extern int pcmpz(precision); /* compare to zero */ +extern int pcmp(precision, precision); /* compare */ +extern int picmp(precision, int); /* single digit cmp */ + +extern precision padd(precision, precision); /* add */ +extern precision psub(precision, precision); /* subtract */ +extern precision pmul(precision, precision); /* multiply */ + +extern precision pdivmod(precision, precision, + precision *q, precision *r); + +extern precision pidiv(precision, int); /* single digit pdiv */ +extern int pimod(precision, int); /* single digit pmod */ +extern void pidivmod(precision, int, /* single pdivmod */ + precision *q, int *r); + +extern precision pneg(precision); /* negate */ +extern precision pabs(precision); /* absolute value */ +extern int podd(precision); /* true if odd */ +extern precision phalf(precision); /* divide by two */ + +extern precision pmin(precision, precision); /* minimum value */ +extern precision pmax(precision, precision); /* maximum value */ + +extern precision prand(precision); /* random number generator */ + +extern precision itop(int); /* int to precision */ +extern precision utop(unsigned); /* unsigned to precision */ +extern precision ltop(long); /* long to precision */ +extern precision ultop(unsigned long); /* unsigned long to precision */ + +extern int ptoi(precision); /* precision to int */ +extern unsigned int ptou(precision); /* precision to unsigned */ +extern long ptol(precision); /* precision to long */ +extern unsigned long ptoul(precision); /* precision to unsigned long */ + +extern precision atop(char *); /* ascii to precision */ +extern char *ptoa(precision); /* precision to ascii */ + +extern int btop(precision *result, /* base to precision */ + char *src, unsigned size, int *digitmap, unsigned radix); + +extern int /* precision to base */ + ptob(precision, char *result, unsigned size, char *alphabet, unsigned radix); + +/* + * Can't do prototyping for these unless stdio.h has been included + */ +#ifdef BUFSIZ +extern precision fgetp(FILE *stream); /* input precision */ +extern int fputp(FILE *stream, precision); /* output precision */ +extern int + fprintp(FILE *stream, precision, int minWidth); /* output within a field */ +#else +extern precision fgetp(); /* input precision */ +extern int fputp(); /* output precision */ +extern int fprintp(); /* output within a field */ +#endif + +extern int putp(precision); /* stdout with '\n' */ + +extern void pshow(precision); /* display debug info */ +extern precision prandnum(); /* debug and profil only */ +extern precision pshift(precision, int); /* shift left */ + +extern precision errorp(int errnum, char *routine, char *message); + +extern precision pzero, pone, ptwo; /* constants 0, 1, and 2 */ +extern precision p_one; /* constant -1 */ + +extern precision psqrt(precision); /* square root */ +extern precision pfactorial(precision); /* factorial */ +extern precision pipow(precision, unsigned); /* unsigned int power */ +extern precision ppow(precision, precision); /* precision power */ +extern precision + ppowmod(precision, precision, precision); /* precision power mod m */ +extern int plogb(precision, precision); /* log base b of n */ + +extern precision dtop(double); /* double to precision */ +extern double ptod(precision); /* precision to double */ + +/* + * vector operations + */ +pvector pvundef(pvector, unsigned size); /* local variable entry */ +void pvdestroy(pvector, unsigned size); /* local variable exit */ + +pvector pvalloc(unsigned size); /* pvec allocate */ +void pvfree(pvector, unsigned size); /* pvec free */ + +pvector pvset(pvector, unsigned size, precision value); + +#else + +/* + * Function versions of above if you still want side effects + */ + +#ifndef __GNUC__ +extern precision pnew(); /* initialization */ +extern precision presult(); /* function result */ +extern precision psetq(); /* quick assignment */ +#endif +extern precision psetv(); /* checked assignment */ +extern precision pparmv(); /* checked parameter */ +extern precision pparmf(); /* unchecked parameter (fn) */ + +extern int pcmpz(); /* compare to zero */ +extern int pcmp(); /* compare */ +extern int picmp(); /* single digit compare */ + +extern precision padd(); /* add */ +extern precision psub(); /* subtract */ +extern precision pmul(); /* multiply */ + +extern precision pdivmod(); /* divide/remainder */ +extern void pidivmod(); /* single digit divide/remainder */ +extern precision pidiv(); /* single digit divide */ +extern int pimod(); /* single digit remainder */ +extern precision pneg(); /* negate */ +extern precision pabs(); /* absolute value */ +extern int podd(); /* true if odd */ +extern precision phalf(); /* divide by two */ + +extern precision pmin(); /* minimum value */ +extern precision pmax(); /* maximum value */ + +extern precision prand(); /* random number generator */ + +extern precision itop(); /* int to precision */ +extern precision utop(); /* unsigned to precision */ +extern precision ltop(); /* long to precision */ +extern precision ultop(); /* unsigned long to precision */ + +extern int ptoi(); /* precision to int */ +extern unsigned int ptou(); /* precision to unsigned */ +extern long ptol(); /* precision to long */ +extern unsigned long ptoul(); /* precision to unsigned long */ + +extern precision atop(); /* ascii to precision */ +extern char *ptoa(); /* precision to ascii */ + +extern int btop(); /* base to precision */ +extern int ptob(); /* precision to base */ + +extern precision fgetp(); /* input a precision */ +extern int fputp(); /* output a precision */ +extern int putp(); /* output precision '\n' to stdout */ +extern int fprintp(); /* output a precision within a field */ + +extern void pshow(); /* display debug info */ +extern precision prandnum(); /* for debug and profil only */ +extern precision pshift(); /* shift left */ + +extern precision errorp(); /* user-substitutable error handler */ + +extern precision pzero, pone, ptwo; /* constants 0, 1, and 2 */ +extern precision p_one; /* constant -1 */ + +extern precision psqrt(); /* square root */ +extern precision pfactorial(); /* factorial */ +extern precision pipow(); /* unsigned int power */ +extern precision ppow(); /* precision power */ +extern precision ppowmod(); /* precision power mod m */ +extern int plogb(); /* log base b of n */ + +extern precision dtop(); /* double to precision */ +extern double ptod(); /* precision to double */ + +/* + * vector operations + */ +pvector pvundef(); /* local variable entry */ +void pvdestroy(); /* local variable exit */ +pvector pvalloc(); /* pvec allocate */ +void pvfree(); /* pvec free */ +pvector pvset(); /* set each element to scaler */ + +#endif diff --git a/benchmarks/benchmarks/cfrac/primes.c b/benchmarks/benchmarks/cfrac/primes.c new file mode 100644 index 0000000..f9dbd84 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/primes.c @@ -0,0 +1,662 @@ +/* + * A table of all primes < 65536 + */ +unsigned int primesize = 6542; + +unsigned short primes[] = { + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, + 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, + 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, + 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, + 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, + 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, + 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, + 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, + 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, + 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, + 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, + 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, + 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, + 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, + 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, + 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, + 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, + 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, + 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, + 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, + 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, + 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, + 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, + 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, + 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, + 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, + 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, + 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, + 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, + 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, + 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, + 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, + 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, + 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, + 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, + 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, + 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, + 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, + 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, + 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, + 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, + 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, + 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, + 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, + 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, + 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, + 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, + 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, + 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, + 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, + 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, + 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, + 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, + 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, + 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, + 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, + 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, + 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, + 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, + 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, + 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, + 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, + 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, + 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, + 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, + 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, + 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, + 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, + 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, + 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, + 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, + 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, + 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, + 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, + 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, + 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, + 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, + 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, + 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, + 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, + 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, + 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, + 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, + 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, + 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, + 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, + 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, + 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, + 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, + 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, + 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, + 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, + 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, + 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, + 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, + 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, + 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, + 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, + 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, + 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, + 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, + 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, + 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, + 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, + 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, + 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, + 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, + 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, + 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, + 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, + 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, + 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, + 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, + 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, + 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, + 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, + 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, + 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, + 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, + 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, + 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, + 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, + 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, + 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, + 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177, + 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259, 10267, 10271, + 10273, 10289, 10301, 10303, 10313, 10321, 10331, 10333, 10337, 10343, + 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, 10459, + 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, + 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, + 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, + 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, + 10861, 10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, + 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, + 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, + 11159, 11161, 11171, 11173, 11177, 11197, 11213, 11239, 11243, 11251, + 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317, 11321, 11329, + 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437, 11443, + 11447, 11467, 11471, 11483, 11489, 11491, 11497, 11503, 11519, 11527, + 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, 11657, + 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, + 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, + 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, + 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, + 12037, 12041, 12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, + 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197, 12203, 12211, + 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289, + 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379, 12391, 12401, + 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479, 12487, + 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553, + 12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, 12637, 12641, + 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, 12739, + 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, + 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, + 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, + 13009, 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, + 13121, 13127, 13147, 13151, 13159, 13163, 13171, 13177, 13183, 13187, + 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, 13297, 13309, + 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411, + 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487, 13499, + 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619, + 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, + 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, 13781, + 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, + 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, + 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, + 14083, 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, + 14207, 14221, 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, + 14327, 14341, 14347, 14369, 14387, 14389, 14401, 14407, 14411, 14419, + 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, 14503, 14519, + 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593, + 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699, + 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, + 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, + 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, + 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, + 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, + 15161, 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, + 15263, 15269, 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, + 15329, 15331, 15349, 15359, 15361, 15373, 15377, 15383, 15391, 15401, + 15413, 15427, 15439, 15443, 15451, 15461, 15467, 15473, 15493, 15497, + 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601, 15607, + 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679, + 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, + 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, + 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, + 15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, + 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, + 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, + 16273, 16301, 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, + 16411, 16417, 16421, 16427, 16433, 16447, 16451, 16453, 16477, 16481, + 16487, 16493, 16519, 16529, 16547, 16553, 16561, 16567, 16573, 16603, + 16607, 16619, 16631, 16633, 16649, 16651, 16657, 16661, 16673, 16691, + 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, 16787, 16811, + 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903, + 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, 16993, + 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, + 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, + 17203, 17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, + 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, + 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, + 17483, 17489, 17491, 17497, 17509, 17519, 17539, 17551, 17569, 17573, + 17579, 17581, 17597, 17599, 17609, 17623, 17627, 17657, 17659, 17669, + 17681, 17683, 17707, 17713, 17729, 17737, 17747, 17749, 17761, 17783, + 17789, 17791, 17807, 17827, 17837, 17839, 17851, 17863, 17881, 17891, + 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, 17959, 17971, + 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, 18059, + 18061, 18077, 18089, 18097, 18119, 18121, 18127, 18131, 18133, 18143, + 18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, 18233, + 18251, 18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, + 18329, 18341, 18353, 18367, 18371, 18379, 18397, 18401, 18413, 18427, + 18433, 18439, 18443, 18451, 18457, 18461, 18481, 18493, 18503, 18517, + 18521, 18523, 18539, 18541, 18553, 18583, 18587, 18593, 18617, 18637, + 18661, 18671, 18679, 18691, 18701, 18713, 18719, 18731, 18743, 18749, + 18757, 18773, 18787, 18793, 18797, 18803, 18839, 18859, 18869, 18899, + 18911, 18913, 18917, 18919, 18947, 18959, 18973, 18979, 19001, 19009, + 19013, 19031, 19037, 19051, 19069, 19073, 19079, 19081, 19087, 19121, + 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, 19219, + 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, + 19333, 19373, 19379, 19381, 19387, 19391, 19403, 19417, 19421, 19423, + 19427, 19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, 19477, + 19483, 19489, 19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, + 19577, 19583, 19597, 19603, 19609, 19661, 19681, 19687, 19697, 19699, + 19709, 19717, 19727, 19739, 19751, 19753, 19759, 19763, 19777, 19793, + 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, 19891, + 19913, 19919, 19927, 19937, 19949, 19961, 19963, 19973, 19979, 19991, + 19993, 19997, 20011, 20021, 20023, 20029, 20047, 20051, 20063, 20071, + 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, 20147, 20149, + 20161, 20173, 20177, 20183, 20201, 20219, 20231, 20233, 20249, 20261, + 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, 20357, + 20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, + 20477, 20479, 20483, 20507, 20509, 20521, 20533, 20543, 20549, 20551, + 20563, 20593, 20599, 20611, 20627, 20639, 20641, 20663, 20681, 20693, + 20707, 20717, 20719, 20731, 20743, 20747, 20749, 20753, 20759, 20771, + 20773, 20789, 20807, 20809, 20849, 20857, 20873, 20879, 20887, 20897, + 20899, 20903, 20921, 20929, 20939, 20947, 20959, 20963, 20981, 20983, + 21001, 21011, 21013, 21017, 21019, 21023, 21031, 21059, 21061, 21067, + 21089, 21101, 21107, 21121, 21139, 21143, 21149, 21157, 21163, 21169, + 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, 21269, 21277, + 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, 21383, + 21391, 21397, 21401, 21407, 21419, 21433, 21467, 21481, 21487, 21491, + 21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, 21563, + 21569, 21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, + 21649, 21661, 21673, 21683, 21701, 21713, 21727, 21737, 21739, 21751, + 21757, 21767, 21773, 21787, 21799, 21803, 21817, 21821, 21839, 21841, + 21851, 21859, 21863, 21871, 21881, 21893, 21911, 21929, 21937, 21943, + 21961, 21977, 21991, 21997, 22003, 22013, 22027, 22031, 22037, 22039, + 22051, 22063, 22067, 22073, 22079, 22091, 22093, 22109, 22111, 22123, + 22129, 22133, 22147, 22153, 22157, 22159, 22171, 22189, 22193, 22229, + 22247, 22259, 22271, 22273, 22277, 22279, 22283, 22291, 22303, 22307, + 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, 22441, + 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, + 22549, 22567, 22571, 22573, 22613, 22619, 22621, 22637, 22639, 22643, + 22651, 22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, 22727, + 22739, 22741, 22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, + 22853, 22859, 22861, 22871, 22877, 22901, 22907, 22921, 22937, 22943, + 22961, 22963, 22973, 22993, 23003, 23011, 23017, 23021, 23027, 23029, + 23039, 23041, 23053, 23057, 23059, 23063, 23071, 23081, 23087, 23099, + 23117, 23131, 23143, 23159, 23167, 23173, 23189, 23197, 23201, 23203, + 23209, 23227, 23251, 23269, 23279, 23291, 23293, 23297, 23311, 23321, + 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, 23431, 23447, + 23459, 23473, 23497, 23509, 23531, 23537, 23539, 23549, 23557, 23561, + 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, 23629, + 23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, + 23747, 23753, 23761, 23767, 23773, 23789, 23801, 23813, 23819, 23827, + 23831, 23833, 23857, 23869, 23873, 23879, 23887, 23893, 23899, 23909, + 23911, 23917, 23929, 23957, 23971, 23977, 23981, 23993, 24001, 24007, + 24019, 24023, 24029, 24043, 24049, 24061, 24071, 24077, 24083, 24091, + 24097, 24103, 24107, 24109, 24113, 24121, 24133, 24137, 24151, 24169, + 24179, 24181, 24197, 24203, 24223, 24229, 24239, 24247, 24251, 24281, + 24317, 24329, 24337, 24359, 24371, 24373, 24379, 24391, 24407, 24413, + 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, 24509, 24517, + 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, 24659, + 24671, 24677, 24683, 24691, 24697, 24709, 24733, 24749, 24763, 24767, + 24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, 24877, + 24889, 24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, + 24979, 24989, 25013, 25031, 25033, 25037, 25057, 25073, 25087, 25097, + 25111, 25117, 25121, 25127, 25147, 25153, 25163, 25169, 25171, 25183, + 25189, 25219, 25229, 25237, 25243, 25247, 25253, 25261, 25301, 25303, + 25307, 25309, 25321, 25339, 25343, 25349, 25357, 25367, 25373, 25391, + 25409, 25411, 25423, 25439, 25447, 25453, 25457, 25463, 25469, 25471, + 25523, 25537, 25541, 25561, 25577, 25579, 25583, 25589, 25601, 25603, + 25609, 25621, 25633, 25639, 25643, 25657, 25667, 25673, 25679, 25693, + 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, 25799, + 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, + 25919, 25931, 25933, 25939, 25943, 25951, 25969, 25981, 25997, 25999, + 26003, 26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, 26111, + 26113, 26119, 26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, + 26209, 26227, 26237, 26249, 26251, 26261, 26263, 26267, 26293, 26297, + 26309, 26317, 26321, 26339, 26347, 26357, 26371, 26387, 26393, 26399, + 26407, 26417, 26423, 26431, 26437, 26449, 26459, 26479, 26489, 26497, + 26501, 26513, 26539, 26557, 26561, 26573, 26591, 26597, 26627, 26633, + 26641, 26647, 26669, 26681, 26683, 26687, 26693, 26699, 26701, 26711, + 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, 26783, 26801, + 26813, 26821, 26833, 26839, 26849, 26861, 26863, 26879, 26881, 26891, + 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, 26987, + 26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, + 27091, 27103, 27107, 27109, 27127, 27143, 27179, 27191, 27197, 27211, + 27239, 27241, 27253, 27259, 27271, 27277, 27281, 27283, 27299, 27329, + 27337, 27361, 27367, 27397, 27407, 27409, 27427, 27431, 27437, 27449, + 27457, 27479, 27481, 27487, 27509, 27527, 27529, 27539, 27541, 27551, + 27581, 27583, 27611, 27617, 27631, 27647, 27653, 27673, 27689, 27691, + 27697, 27701, 27733, 27737, 27739, 27743, 27749, 27751, 27763, 27767, + 27773, 27779, 27791, 27793, 27799, 27803, 27809, 27817, 27823, 27827, + 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, 27943, 27947, + 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, 28051, + 28057, 28069, 28081, 28087, 28097, 28099, 28109, 28111, 28123, 28151, + 28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, 28283, + 28289, 28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, + 28409, 28411, 28429, 28433, 28439, 28447, 28463, 28477, 28493, 28499, + 28513, 28517, 28537, 28541, 28547, 28549, 28559, 28571, 28573, 28579, + 28591, 28597, 28603, 28607, 28619, 28621, 28627, 28631, 28643, 28649, + 28657, 28661, 28663, 28669, 28687, 28697, 28703, 28711, 28723, 28729, + 28751, 28753, 28759, 28771, 28789, 28793, 28807, 28813, 28817, 28837, + 28843, 28859, 28867, 28871, 28879, 28901, 28909, 28921, 28927, 28933, + 28949, 28961, 28979, 29009, 29017, 29021, 29023, 29027, 29033, 29059, + 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, 29167, + 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, + 29269, 29287, 29297, 29303, 29311, 29327, 29333, 29339, 29347, 29363, + 29383, 29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, 29443, + 29453, 29473, 29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, + 29581, 29587, 29599, 29611, 29629, 29633, 29641, 29663, 29669, 29671, + 29683, 29717, 29723, 29741, 29753, 29759, 29761, 29789, 29803, 29819, + 29833, 29837, 29851, 29863, 29867, 29873, 29879, 29881, 29917, 29921, + 29927, 29947, 29959, 29983, 29989, 30011, 30013, 30029, 30047, 30059, + 30071, 30089, 30091, 30097, 30103, 30109, 30113, 30119, 30133, 30137, + 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, 30223, 30241, + 30253, 30259, 30269, 30271, 30293, 30307, 30313, 30319, 30323, 30341, + 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, 30469, + 30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, + 30577, 30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689, + 30697, 30703, 30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803, + 30809, 30817, 30829, 30839, 30841, 30851, 30853, 30859, 30869, 30871, + 30881, 30893, 30911, 30931, 30937, 30941, 30949, 30971, 30977, 30983, + 31013, 31019, 31033, 31039, 31051, 31063, 31069, 31079, 31081, 31091, + 31121, 31123, 31139, 31147, 31151, 31153, 31159, 31177, 31181, 31183, + 31189, 31193, 31219, 31223, 31231, 31237, 31247, 31249, 31253, 31259, + 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, 31337, 31357, + 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, 31511, + 31513, 31517, 31531, 31541, 31543, 31547, 31567, 31573, 31583, 31601, + 31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, 31721, + 31723, 31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, + 31847, 31849, 31859, 31873, 31883, 31891, 31907, 31957, 31963, 31973, + 31981, 31991, 32003, 32009, 32027, 32029, 32051, 32057, 32059, 32063, + 32069, 32077, 32083, 32089, 32099, 32117, 32119, 32141, 32143, 32159, + 32173, 32183, 32189, 32191, 32203, 32213, 32233, 32237, 32251, 32257, + 32261, 32297, 32299, 32303, 32309, 32321, 32323, 32327, 32341, 32353, + 32359, 32363, 32369, 32371, 32377, 32381, 32401, 32411, 32413, 32423, + 32429, 32441, 32443, 32467, 32479, 32491, 32497, 32503, 32507, 32531, + 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, 32609, + 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, + 32719, 32749, 32771, 32779, 32783, 32789, 32797, 32801, 32803, 32831, + 32833, 32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, 32939, + 32941, 32957, 32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, + 33029, 33037, 33049, 33053, 33071, 33073, 33083, 33091, 33107, 33113, + 33119, 33149, 33151, 33161, 33179, 33181, 33191, 33199, 33203, 33211, + 33223, 33247, 33287, 33289, 33301, 33311, 33317, 33329, 33331, 33343, + 33347, 33349, 33353, 33359, 33377, 33391, 33403, 33409, 33413, 33427, + 33457, 33461, 33469, 33479, 33487, 33493, 33503, 33521, 33529, 33533, + 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, 33601, 33613, + 33617, 33619, 33623, 33629, 33637, 33641, 33647, 33679, 33703, 33713, + 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, 33797, + 33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, + 33911, 33923, 33931, 33937, 33941, 33961, 33967, 33997, 34019, 34031, + 34033, 34039, 34057, 34061, 34123, 34127, 34129, 34141, 34147, 34157, + 34159, 34171, 34183, 34211, 34213, 34217, 34231, 34253, 34259, 34261, + 34267, 34273, 34283, 34297, 34301, 34303, 34313, 34319, 34327, 34337, + 34351, 34361, 34367, 34369, 34381, 34403, 34421, 34429, 34439, 34457, + 34469, 34471, 34483, 34487, 34499, 34501, 34511, 34513, 34519, 34537, + 34543, 34549, 34583, 34589, 34591, 34603, 34607, 34613, 34631, 34649, + 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, 34729, 34739, + 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, 34847, + 34849, 34871, 34877, 34883, 34897, 34913, 34919, 34939, 34949, 34961, + 34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, 35083, + 35089, 35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, + 35171, 35201, 35221, 35227, 35251, 35257, 35267, 35279, 35281, 35291, + 35311, 35317, 35323, 35327, 35339, 35353, 35363, 35381, 35393, 35401, + 35407, 35419, 35423, 35437, 35447, 35449, 35461, 35491, 35507, 35509, + 35521, 35527, 35531, 35533, 35537, 35543, 35569, 35573, 35591, 35593, + 35597, 35603, 35617, 35671, 35677, 35729, 35731, 35747, 35753, 35759, + 35771, 35797, 35801, 35803, 35809, 35831, 35837, 35839, 35851, 35863, + 35869, 35879, 35897, 35899, 35911, 35923, 35933, 35951, 35963, 35969, + 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, 36061, + 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, + 36187, 36191, 36209, 36217, 36229, 36241, 36251, 36263, 36269, 36277, + 36293, 36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, 36383, + 36389, 36433, 36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, + 36523, 36527, 36529, 36541, 36551, 36559, 36563, 36571, 36583, 36587, + 36599, 36607, 36629, 36637, 36643, 36653, 36671, 36677, 36683, 36691, + 36697, 36709, 36713, 36721, 36739, 36749, 36761, 36767, 36779, 36781, + 36787, 36791, 36793, 36809, 36821, 36833, 36847, 36857, 36871, 36877, + 36887, 36899, 36901, 36913, 36919, 36923, 36929, 36931, 36943, 36947, + 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, 37049, 37057, + 37061, 37087, 37097, 37117, 37123, 37139, 37159, 37171, 37181, 37189, + 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, 37309, + 37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, + 37409, 37423, 37441, 37447, 37463, 37483, 37489, 37493, 37501, 37507, + 37511, 37517, 37529, 37537, 37547, 37549, 37561, 37567, 37571, 37573, + 37579, 37589, 37591, 37607, 37619, 37633, 37643, 37649, 37657, 37663, + 37691, 37693, 37699, 37717, 37747, 37781, 37783, 37799, 37811, 37813, + 37831, 37847, 37853, 37861, 37871, 37879, 37889, 37897, 37907, 37951, + 37957, 37963, 37967, 37987, 37991, 37993, 37997, 38011, 38039, 38047, + 38053, 38069, 38083, 38113, 38119, 38149, 38153, 38167, 38177, 38183, + 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, 38273, 38281, + 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, 38371, + 38377, 38393, 38431, 38447, 38449, 38453, 38459, 38461, 38501, 38543, + 38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, 38639, + 38651, 38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, + 38723, 38729, 38737, 38747, 38749, 38767, 38783, 38791, 38803, 38821, + 38833, 38839, 38851, 38861, 38867, 38873, 38891, 38903, 38917, 38921, + 38923, 38933, 38953, 38959, 38971, 38977, 38993, 39019, 39023, 39041, + 39043, 39047, 39079, 39089, 39097, 39103, 39107, 39113, 39119, 39133, + 39139, 39157, 39161, 39163, 39181, 39191, 39199, 39209, 39217, 39227, + 39229, 39233, 39239, 39241, 39251, 39293, 39301, 39313, 39317, 39323, + 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397, 39409, 39419, + 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, 39541, + 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, + 39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769, + 39779, 39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857, + 39863, 39869, 39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, + 39979, 39983, 39989, 40009, 40013, 40031, 40037, 40039, 40063, 40087, + 40093, 40099, 40111, 40123, 40127, 40129, 40151, 40153, 40163, 40169, + 40177, 40189, 40193, 40213, 40231, 40237, 40241, 40253, 40277, 40283, + 40289, 40343, 40351, 40357, 40361, 40387, 40423, 40427, 40429, 40433, + 40459, 40471, 40483, 40487, 40493, 40499, 40507, 40519, 40529, 40531, + 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, 40637, 40639, + 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771, 40787, + 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867, + 40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, + 40993, 41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081, + 41113, 41117, 41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183, + 41189, 41201, 41203, 41213, 41221, 41227, 41231, 41233, 41243, 41257, + 41263, 41269, 41281, 41299, 41333, 41341, 41351, 41357, 41381, 41387, + 41389, 41399, 41411, 41413, 41443, 41453, 41467, 41479, 41491, 41507, + 41513, 41519, 41521, 41539, 41543, 41549, 41579, 41593, 41597, 41603, + 41609, 41611, 41617, 41621, 41627, 41641, 41647, 41651, 41659, 41669, + 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, 41777, 41801, + 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, 41897, + 41903, 41911, 41927, 41941, 41947, 41953, 41957, 41959, 41969, 41981, + 41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, 42073, + 42083, 42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, + 42193, 42197, 42209, 42221, 42223, 42227, 42239, 42257, 42281, 42283, + 42293, 42299, 42307, 42323, 42331, 42337, 42349, 42359, 42373, 42379, + 42391, 42397, 42403, 42407, 42409, 42433, 42437, 42443, 42451, 42457, + 42461, 42463, 42467, 42473, 42487, 42491, 42499, 42509, 42533, 42557, + 42569, 42571, 42577, 42589, 42611, 42641, 42643, 42649, 42667, 42677, + 42683, 42689, 42697, 42701, 42703, 42709, 42719, 42727, 42737, 42743, + 42751, 42767, 42773, 42787, 42793, 42797, 42821, 42829, 42839, 42841, + 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, 42953, + 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, + 43063, 43067, 43093, 43103, 43117, 43133, 43151, 43159, 43177, 43189, + 43201, 43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, 43319, + 43321, 43331, 43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, + 43457, 43481, 43487, 43499, 43517, 43541, 43543, 43573, 43577, 43579, + 43591, 43597, 43607, 43609, 43613, 43627, 43633, 43649, 43651, 43661, + 43669, 43691, 43711, 43717, 43721, 43753, 43759, 43777, 43781, 43783, + 43787, 43789, 43793, 43801, 43853, 43867, 43889, 43891, 43913, 43933, + 43943, 43951, 43961, 43963, 43969, 43973, 43987, 43991, 43997, 44017, + 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, 44089, 44101, + 44111, 44119, 44123, 44129, 44131, 44159, 44171, 44179, 44189, 44201, + 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, 44279, + 44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, + 44453, 44483, 44491, 44497, 44501, 44507, 44519, 44531, 44533, 44537, + 44543, 44549, 44563, 44579, 44587, 44617, 44621, 44623, 44633, 44641, + 44647, 44651, 44657, 44683, 44687, 44699, 44701, 44711, 44729, 44741, + 44753, 44771, 44773, 44777, 44789, 44797, 44809, 44819, 44839, 44843, + 44851, 44867, 44879, 44887, 44893, 44909, 44917, 44927, 44939, 44953, + 44959, 44963, 44971, 44983, 44987, 45007, 45013, 45053, 45061, 45077, + 45083, 45119, 45121, 45127, 45131, 45137, 45139, 45161, 45179, 45181, + 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, 45293, 45307, + 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, 45403, + 45413, 45427, 45433, 45439, 45481, 45491, 45497, 45503, 45523, 45533, + 45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, 45641, + 45659, 45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, + 45763, 45767, 45779, 45817, 45821, 45823, 45827, 45833, 45841, 45853, + 45863, 45869, 45887, 45893, 45943, 45949, 45953, 45959, 45971, 45979, + 45989, 46021, 46027, 46049, 46051, 46061, 46073, 46091, 46093, 46099, + 46103, 46133, 46141, 46147, 46153, 46171, 46181, 46183, 46187, 46199, + 46219, 46229, 46237, 46261, 46271, 46273, 46279, 46301, 46307, 46309, + 46327, 46337, 46349, 46351, 46381, 46399, 46411, 46439, 46441, 46447, + 46451, 46457, 46471, 46477, 46489, 46499, 46507, 46511, 46523, 46549, + 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, 46643, + 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, + 46751, 46757, 46769, 46771, 46807, 46811, 46817, 46819, 46829, 46831, + 46853, 46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, 46993, + 46997, 47017, 47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, + 47123, 47129, 47137, 47143, 47147, 47149, 47161, 47189, 47207, 47221, + 47237, 47251, 47269, 47279, 47287, 47293, 47297, 47303, 47309, 47317, + 47339, 47351, 47353, 47363, 47381, 47387, 47389, 47407, 47417, 47419, + 47431, 47441, 47459, 47491, 47497, 47501, 47507, 47513, 47521, 47527, + 47533, 47543, 47563, 47569, 47581, 47591, 47599, 47609, 47623, 47629, + 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, 47713, 47717, + 47737, 47741, 47743, 47777, 47779, 47791, 47797, 47807, 47809, 47819, + 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, 47939, + 47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, + 48073, 48079, 48091, 48109, 48119, 48121, 48131, 48157, 48163, 48179, + 48187, 48193, 48197, 48221, 48239, 48247, 48259, 48271, 48281, 48299, + 48311, 48313, 48337, 48341, 48353, 48371, 48383, 48397, 48407, 48409, + 48413, 48437, 48449, 48463, 48473, 48479, 48481, 48487, 48491, 48497, + 48523, 48527, 48533, 48539, 48541, 48563, 48571, 48589, 48593, 48611, + 48619, 48623, 48647, 48649, 48661, 48673, 48677, 48679, 48731, 48733, + 48751, 48757, 48761, 48767, 48779, 48781, 48787, 48799, 48809, 48817, + 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, 48889, 48907, + 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, 49033, + 49037, 49043, 49057, 49069, 49081, 49103, 49109, 49117, 49121, 49123, + 49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, 49211, + 49223, 49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, + 49363, 49367, 49369, 49391, 49393, 49409, 49411, 49417, 49429, 49433, + 49451, 49459, 49463, 49477, 49481, 49499, 49523, 49529, 49531, 49537, + 49547, 49549, 49559, 49597, 49603, 49613, 49627, 49633, 49639, 49663, + 49667, 49669, 49681, 49697, 49711, 49727, 49739, 49741, 49747, 49757, + 49783, 49787, 49789, 49801, 49807, 49811, 49823, 49831, 49843, 49853, + 49871, 49877, 49891, 49919, 49921, 49927, 49937, 49939, 49943, 49957, + 49991, 49993, 49999, 50021, 50023, 50033, 50047, 50051, 50053, 50069, + 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, 50147, + 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, + 50287, 50291, 50311, 50321, 50329, 50333, 50341, 50359, 50363, 50377, + 50383, 50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, 50503, + 50513, 50527, 50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, + 50599, 50627, 50647, 50651, 50671, 50683, 50707, 50723, 50741, 50753, + 50767, 50773, 50777, 50789, 50821, 50833, 50839, 50849, 50857, 50867, + 50873, 50891, 50893, 50909, 50923, 50929, 50951, 50957, 50969, 50971, + 50989, 50993, 51001, 51031, 51043, 51047, 51059, 51061, 51071, 51109, + 51131, 51133, 51137, 51151, 51157, 51169, 51193, 51197, 51199, 51203, + 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, 51307, 51329, + 51341, 51343, 51347, 51349, 51361, 51383, 51407, 51413, 51419, 51421, + 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, 51487, + 51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, + 51599, 51607, 51613, 51631, 51637, 51647, 51659, 51673, 51679, 51683, + 51691, 51713, 51719, 51721, 51749, 51767, 51769, 51787, 51797, 51803, + 51817, 51827, 51829, 51839, 51853, 51859, 51869, 51871, 51893, 51899, + 51907, 51913, 51929, 51941, 51949, 51971, 51973, 51977, 51991, 52009, + 52021, 52027, 52051, 52057, 52067, 52069, 52081, 52103, 52121, 52127, + 52147, 52153, 52163, 52177, 52181, 52183, 52189, 52201, 52223, 52237, + 52249, 52253, 52259, 52267, 52289, 52291, 52301, 52313, 52321, 52361, + 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, 52489, 52501, + 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, 52579, + 52583, 52609, 52627, 52631, 52639, 52667, 52673, 52691, 52697, 52709, + 52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, 52813, + 52817, 52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, + 52937, 52951, 52957, 52963, 52967, 52973, 52981, 52999, 53003, 53017, + 53047, 53051, 53069, 53077, 53087, 53089, 53093, 53101, 53113, 53117, + 53129, 53147, 53149, 53161, 53171, 53173, 53189, 53197, 53201, 53231, + 53233, 53239, 53267, 53269, 53279, 53281, 53299, 53309, 53323, 53327, + 53353, 53359, 53377, 53381, 53401, 53407, 53411, 53419, 53437, 53441, + 53453, 53479, 53503, 53507, 53527, 53549, 53551, 53569, 53591, 53593, + 53597, 53609, 53611, 53617, 53623, 53629, 53633, 53639, 53653, 53657, + 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, 53783, + 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, + 53897, 53899, 53917, 53923, 53927, 53939, 53951, 53959, 53987, 53993, + 54001, 54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, 54121, + 54133, 54139, 54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, + 54277, 54287, 54293, 54311, 54319, 54323, 54331, 54347, 54361, 54367, + 54371, 54377, 54401, 54403, 54409, 54413, 54419, 54421, 54437, 54443, + 54449, 54469, 54493, 54497, 54499, 54503, 54517, 54521, 54539, 54541, + 54547, 54559, 54563, 54577, 54581, 54583, 54601, 54617, 54623, 54629, + 54631, 54647, 54667, 54673, 54679, 54709, 54713, 54721, 54727, 54751, + 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, 54869, 54877, + 54881, 54907, 54917, 54919, 54941, 54949, 54959, 54973, 54979, 54983, + 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, 55103, + 55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, + 55219, 55229, 55243, 55249, 55259, 55291, 55313, 55331, 55333, 55337, + 55339, 55343, 55351, 55373, 55381, 55399, 55411, 55439, 55441, 55457, + 55469, 55487, 55501, 55511, 55529, 55541, 55547, 55579, 55589, 55603, + 55609, 55619, 55621, 55631, 55633, 55639, 55661, 55663, 55667, 55673, + 55681, 55691, 55697, 55711, 55717, 55721, 55733, 55763, 55787, 55793, + 55799, 55807, 55813, 55817, 55819, 55823, 55829, 55837, 55843, 55849, + 55871, 55889, 55897, 55901, 55903, 55921, 55927, 55931, 55933, 55949, + 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, 56081, 56087, + 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, 56179, + 56197, 56207, 56209, 56237, 56239, 56249, 56263, 56267, 56269, 56299, + 56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, 56431, + 56437, 56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, + 56509, 56519, 56527, 56531, 56533, 56543, 56569, 56591, 56597, 56599, + 56611, 56629, 56633, 56659, 56663, 56671, 56681, 56687, 56701, 56711, + 56713, 56731, 56737, 56747, 56767, 56773, 56779, 56783, 56807, 56809, + 56813, 56821, 56827, 56843, 56857, 56873, 56891, 56893, 56897, 56909, + 56911, 56921, 56923, 56929, 56941, 56951, 56957, 56963, 56983, 56989, + 56993, 56999, 57037, 57041, 57047, 57059, 57073, 57077, 57089, 57097, + 57107, 57119, 57131, 57139, 57143, 57149, 57163, 57173, 57179, 57191, + 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, 57283, + 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, + 57397, 57413, 57427, 57457, 57467, 57487, 57493, 57503, 57527, 57529, + 57557, 57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, 57653, + 57667, 57679, 57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, + 57751, 57773, 57781, 57787, 57791, 57793, 57803, 57809, 57829, 57839, + 57847, 57853, 57859, 57881, 57899, 57901, 57917, 57923, 57943, 57947, + 57973, 57977, 57991, 58013, 58027, 58031, 58043, 58049, 58057, 58061, + 58067, 58073, 58099, 58109, 58111, 58129, 58147, 58151, 58153, 58169, + 58171, 58189, 58193, 58199, 58207, 58211, 58217, 58229, 58231, 58237, + 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, 58369, 58379, + 58391, 58393, 58403, 58411, 58417, 58427, 58439, 58441, 58451, 58453, + 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, 58601, + 58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, + 58727, 58733, 58741, 58757, 58763, 58771, 58787, 58789, 58831, 58889, + 58897, 58901, 58907, 58909, 58913, 58921, 58937, 58943, 58963, 58967, + 58979, 58991, 58997, 59009, 59011, 59021, 59023, 59029, 59051, 59053, + 59063, 59069, 59077, 59083, 59093, 59107, 59113, 59119, 59123, 59141, + 59149, 59159, 59167, 59183, 59197, 59207, 59209, 59219, 59221, 59233, + 59239, 59243, 59263, 59273, 59281, 59333, 59341, 59351, 59357, 59359, + 59369, 59377, 59387, 59393, 59399, 59407, 59417, 59419, 59441, 59443, + 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, 59539, 59557, + 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, 59659, + 59663, 59669, 59671, 59693, 59699, 59707, 59723, 59729, 59743, 59747, + 59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, 59887, + 59921, 59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, + 60037, 60041, 60077, 60083, 60089, 60091, 60101, 60103, 60107, 60127, + 60133, 60139, 60149, 60161, 60167, 60169, 60209, 60217, 60223, 60251, + 60257, 60259, 60271, 60289, 60293, 60317, 60331, 60337, 60343, 60353, + 60373, 60383, 60397, 60413, 60427, 60443, 60449, 60457, 60493, 60497, + 60509, 60521, 60527, 60539, 60589, 60601, 60607, 60611, 60617, 60623, + 60631, 60637, 60647, 60649, 60659, 60661, 60679, 60689, 60703, 60719, + 60727, 60733, 60737, 60757, 60761, 60763, 60773, 60779, 60793, 60811, + 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, 60919, + 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, + 61051, 61057, 61091, 61099, 61121, 61129, 61141, 61151, 61153, 61169, + 61211, 61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, 61333, + 61339, 61343, 61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, + 61463, 61469, 61471, 61483, 61487, 61493, 61507, 61511, 61519, 61543, + 61547, 61553, 61559, 61561, 61583, 61603, 61609, 61613, 61627, 61631, + 61637, 61643, 61651, 61657, 61667, 61673, 61681, 61687, 61703, 61717, + 61723, 61729, 61751, 61757, 61781, 61813, 61819, 61837, 61843, 61861, + 61871, 61879, 61909, 61927, 61933, 61949, 61961, 61967, 61979, 61981, + 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, 62057, 62071, + 62081, 62099, 62119, 62129, 62131, 62137, 62141, 62143, 62171, 62189, + 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, 62303, + 62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, + 62467, 62473, 62477, 62483, 62497, 62501, 62507, 62533, 62539, 62549, + 62563, 62581, 62591, 62597, 62603, 62617, 62627, 62633, 62639, 62653, + 62659, 62683, 62687, 62701, 62723, 62731, 62743, 62753, 62761, 62773, + 62791, 62801, 62819, 62827, 62851, 62861, 62869, 62873, 62897, 62903, + 62921, 62927, 62929, 62939, 62969, 62971, 62981, 62983, 62987, 62989, + 63029, 63031, 63059, 63067, 63073, 63079, 63097, 63103, 63113, 63127, + 63131, 63149, 63179, 63197, 63199, 63211, 63241, 63247, 63277, 63281, + 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, 63361, 63367, + 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, 63463, + 63467, 63473, 63487, 63493, 63499, 63521, 63527, 63533, 63541, 63559, + 63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, 63647, + 63649, 63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, + 63727, 63737, 63743, 63761, 63773, 63781, 63793, 63799, 63803, 63809, + 63823, 63839, 63841, 63853, 63857, 63863, 63901, 63907, 63913, 63929, + 63949, 63977, 63997, 64007, 64013, 64019, 64033, 64037, 64063, 64067, + 64081, 64091, 64109, 64123, 64151, 64153, 64157, 64171, 64187, 64189, + 64217, 64223, 64231, 64237, 64271, 64279, 64283, 64301, 64303, 64319, + 64327, 64333, 64373, 64381, 64399, 64403, 64433, 64439, 64451, 64453, + 64483, 64489, 64499, 64513, 64553, 64567, 64577, 64579, 64591, 64601, + 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, 64693, + 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, + 64853, 64871, 64877, 64879, 64891, 64901, 64919, 64921, 64927, 64937, + 64951, 64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, 65063, + 65071, 65089, 65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, + 65167, 65171, 65173, 65179, 65183, 65203, 65213, 65239, 65257, 65267, + 65269, 65287, 65293, 65309, 65323, 65327, 65353, 65357, 65371, 65381, + 65393, 65407, 65413, 65419, 65423, 65437, 65447, 65449, 65479, 65497, + 65519, 65521, 1 +}; diff --git a/benchmarks/benchmarks/cfrac/primes.h b/benchmarks/benchmarks/cfrac/primes.h new file mode 100644 index 0000000..206f480 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/primes.h @@ -0,0 +1,2 @@ +extern unsigned int primesize; +extern unsigned short primes[]; diff --git a/benchmarks/benchmarks/cfrac/psqrt.c b/benchmarks/benchmarks/cfrac/psqrt.c new file mode 100644 index 0000000..00531a6 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/psqrt.c @@ -0,0 +1,29 @@ +#include "precision.h" + +/* + * Square root + */ +precision psqrt(y) + precision y; +{ + int i; + precision x = pUndef, lastx = pUndef; + + i = pcmpz(pparm(y)); + if (i == 0) { /* if y == 0 */ + pset(&lastx, pzero); + } else if (i < 0) { /* if y negative */ + pset(&x, errorp(PDOMAIN, "psqrt", "negative argument")); + } else { + pset(&x, y); + do { + pset(&lastx, x); + pset(&x, phalf(padd(x, pdiv(y, x)))); + } while (plt(x, lastx)); + } + + pdestroy(x); + + pdestroy(y); + return presult(lastx); +} diff --git a/benchmarks/benchmarks/cfrac/psub.c b/benchmarks/benchmarks/cfrac/psub.c new file mode 100644 index 0000000..d887287 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/psub.c @@ -0,0 +1,92 @@ +#include "pdefs.h" +#include "precision.h" +#include + +#ifdef ASM_16BIT +#include "asm16bit.h" +#endif + +/* + * Subtract u from v (assumes normalized) + */ +precision psub(u, v) +#ifndef ASM_16BIT + precision u, v; +{ + register digitPtr HiDigit, wPtr, uPtr; + register digitPtr vPtr; +#else + register precision u, v; +{ + register digitPtr wPtr, uPtr; +#endif + precision w; + register accumulator temp; +#ifndef ASM_16BIT + register digit noborrow; +#endif + register int i; + + (void) pparm(u); + (void) pparm(v); + if (u->sign != v->sign) { /* Are we actually adding? */ + w = pUndef; + v->sign = !v->sign; /* may generate -0 */ + pset(&w, padd(u, v)); + v->sign = !v->sign; + } else { + i = pcmp(u, v); + if (u->sign) i = -i; /* compare magnitudes only */ + + if (i < 0) { + w = u; u = v; v = w; /* make u the largest */ + } + + w = palloc(u->size); /* may produce much wasted storage */ + if (w == pUndef) return w; + + if (i < 0) w->sign = !u->sign; else w->sign = u->sign; + + uPtr = u->value; + wPtr = w->value; +#ifndef ASM_16BIT + vPtr = v->value; + noborrow = 1; + + HiDigit = v->value + v->size; /* digits in both args */ + do { + temp = (BASE-1) - *vPtr++; /* 0 <= temp < base */ + temp += *uPtr++; /* 0 <= temp < 2*base-1 */ + temp += noborrow; /* 0 <= temp < 2*base */ + noborrow = divBase(temp); /* 0 <= noborrow <= 1 */ + *wPtr++ = modBase(temp); + } while (vPtr < HiDigit); + + HiDigit = u->value + u->size; /* propagate borrow */ + while (uPtr < HiDigit) { + temp = (BASE-1) + *uPtr++; + temp += noborrow; /* 0 <= temp < 2 * base */ + noborrow = divBase(temp); /* 0 <= noborrow <= 1 */ + *wPtr++ = modBase(temp); + } /* noborrow = 1 */ +#else + i = v->size; + temp = u->size - i; + if (temp > 0) { + memcpy(wPtr + i, uPtr + i, temp * sizeof(digit)); + } + if (memsubw(wPtr, uPtr, v->value, i)) { /* trashes uPtr */ + memdecw(wPtr + i, temp); + } + wPtr += w->size; +#endif + do { /* normalize */ + if (*--wPtr != 0) break; + } while (wPtr > w->value); + w->size = (wPtr - w->value) + 1; + } + + pdestroy(u); + pdestroy(v); + return presult(w); +} diff --git a/benchmarks/benchmarks/cfrac/ptoa.c b/benchmarks/benchmarks/cfrac/ptoa.c new file mode 100644 index 0000000..812e8c7 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/ptoa.c @@ -0,0 +1,71 @@ +#include +#include "pdefs.h" +#include "pcvt.h" +#include "precision.h" + +/* + * Return the character string decimal value of a Precision + */ +#if (BASE > 10) +#define CONDIGIT(d) ((d) < 10 ? (d) + '0' : (d) + 'a'-10) +#else +#define CONDIGIT(d) ((d) + '0') +#endif + +char *ptoa(u) + precision u; +{ + register accumulator temp; + register char *dPtr; + char *d; + int i = 0; + unsigned int consize; + precision r, v, pbase; + register int j; + + (void) pparm(u); + r = pUndef; + v = pUndef; + pbase = pUndef; + + consize = (unsigned int) u->size; + if (consize > MAXINT / aDigits) { + consize = (consize / pDigits) * aDigits; + } else { + consize = (consize * aDigits) / pDigits; + } + + consize += aDigitLog + 2; /* leading 0's, sign, & '\0' */ + d = (char *) allocate((unsigned int) consize); + if (d == (char *) 0) return d; + + pset(&v, pabs(u)); + pset(&pbase, utop(aDigit)); + + dPtr = d + consize; + *--dPtr = '\0'; /* null terminate string */ + i = u->sign; /* save sign */ + do { + pdivmod(v, pbase, &v, &r); + temp = ptou(r); /* Assumes unsigned and accumulator same! */ + j = aDigitLog; + do { + *--dPtr = CONDIGIT(temp % aBase); /* remainder */ + temp = temp / aBase; + } while (--j > 0); + } while (pnez(v)); + + while (*dPtr == '0') dPtr++; /* toss leading zero's */ + if (*dPtr == '\0') --dPtr; /* but don't waste zero! */ + if (i) *--dPtr = '-'; + if (dPtr > d) { /* ASSUME copied from lower to higher! */ + (void) memmove(d, dPtr, consize - (dPtr - d)); + } + + pdestroy(pbase); + pdestroy(v); + pdestroy(r); + + pdestroy(u); + return d; +} diff --git a/benchmarks/benchmarks/cfrac/ptob.c b/benchmarks/benchmarks/cfrac/ptob.c new file mode 100644 index 0000000..d5b04c1 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/ptob.c @@ -0,0 +1,81 @@ +#include "pdefs.h" +#include "precision.h" + +/* + * Convert a precision to a given base (the sign is ignored) + * + * Input: + * u - the number to convert + * dest - Where to put the ASCII representation radix + * WARNING! Not '\0' terminated, this is an exact image + * size - the number of digits of dest. + * (alphabet[0] padded on left) + * if size is too small, truncation occurs on left + * alphabet - A mapping from each radix digit to it's character digit + * (note: '\0' is perfectly OK as a digit) + * radix - The size of the alphabet, and the conversion radix + * 2 <= radix < 256. + * + * Returns: + * -1 if invalid radix + * 0 if successful + * >0 the number didn't fit + */ +int ptob(u, dest, size, alphabet, radix) + precision u; /* the number to convert */ + char *dest; /* where to place the converted ascii */ + unsigned int size; /* the size of the result in characters */ + char *alphabet; /* the character set forming the radix */ + register unsigned int radix; /* the size of the character set */ +{ + register accumulator temp; + register unsigned int i; + register char *chp; + unsigned int lgclump; + int res = 0; + + precision r = pUndef, v = pUndef, pbase = pUndef; + + if (radix > 256 || radix < 2) return -1; + if (size == 0) return 1; + + (void) pparm(u); + temp = radix; + i = 1; + while (temp * radix > temp) { + temp *= radix; + i++; + } + lgclump = i; + + pset(&v, pabs(u)); + pset(&pbase, utop(temp)); /* assumes accumulator and int are the same! */ + + chp = dest + size; + do { + pdivmod(v, pbase, &v, &r); + temp = ptou(r); /* assumes accumulator and int are the same! */ + i = lgclump; + do { + *--chp = alphabet[temp % radix]; /* remainder */ + temp = temp / radix; + if (chp == dest) goto bail; + } while (--i > 0); + } while pnez(v); + + if (chp > dest) do { + *--chp = *alphabet; + } while (chp > dest); + +bail: + if (pnez(v) || temp != 0) { /* check for overflow */ + res = 1; + } + + pdestroy(pbase); + pdestroy(v); + pdestroy(r); + + pdestroy(u); + return res; +} diff --git a/benchmarks/benchmarks/cfrac/ptou.c b/benchmarks/benchmarks/cfrac/ptou.c new file mode 100644 index 0000000..b8ca07b --- /dev/null +++ b/benchmarks/benchmarks/cfrac/ptou.c @@ -0,0 +1,31 @@ +#include "pdefs.h" +#include "pcvt.h" +#include "precision.h" + +/* + * Precision to unsigned + */ +unsigned int ptou(u) + precision u; +{ + register digitPtr uPtr; + register accumulator temp; + + (void) pparm(u); + if (u->sign) { + temp = (unsigned long) errorp(PDOMAIN, "ptou", "negative argument"); + } else { + uPtr = u->value + u->size; + temp = 0; + do { + if (temp > divBase(MAXUNSIGNED - *--uPtr)) { + temp = (unsigned long) errorp(POVERFLOW, "ptou", "overflow"); + break; + } + temp = mulBase(temp); + temp += *uPtr; + } while (uPtr > u->value); + } + pdestroy(u); + return (unsigned int) temp; +} diff --git a/benchmarks/benchmarks/cfrac/seive.h b/benchmarks/benchmarks/cfrac/seive.h new file mode 100644 index 0000000..2e1cb85 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/seive.h @@ -0,0 +1,3 @@ +extern unsigned long seivesize; + +extern unsigned char seive[]; diff --git a/benchmarks/benchmarks/cfrac/utop.c b/benchmarks/benchmarks/cfrac/utop.c new file mode 100644 index 0000000..4d87c04 --- /dev/null +++ b/benchmarks/benchmarks/cfrac/utop.c @@ -0,0 +1,25 @@ +#include "pdefs.h" +#include "pcvt.h" +#include "precision.h" + +/* + * Unsigned to Precision + */ +precision utop(i) + register unsigned int i; +{ + register digitPtr uPtr; + register precision u = palloc(INTSIZE); + + if (u == pUndef) return pUndef; + + u->sign = false; + uPtr = u->value; + do { + *uPtr++ = modBase(i); + i = divBase(i); + } while (i != 0); + + u->size = (uPtr - u->value); + return presult(u); +} diff --git a/benchmarks/benchmarks/espresso/README.md b/benchmarks/benchmarks/espresso/README.md new file mode 100644 index 0000000..7cc0d93 --- /dev/null +++ b/benchmarks/benchmarks/espresso/README.md @@ -0,0 +1,22 @@ +``` +Oct Tools Distribution 4.0 + +Copyright (c) 1988, 1989, 1990, Regents of the University of California. +All rights reserved. + +Use and copying of this software and preparation of derivative works +based upon this software are permitted. However, any distribution of +this software or derivative works must include the above copyright +notice. + +This software is made available AS IS, and neither the Electronics +Research Laboratory or the University of California make any +warranty about the software, its performance or its conformity to +any specification. + +Suggestions, comments, or improvements are welcome and should be +addressed to: + + octtools@eros.berkeley.edu + ..!ucbvax!eros!octtools +``` diff --git a/benchmarks/benchmarks/espresso/ansi.h b/benchmarks/benchmarks/espresso/ansi.h new file mode 100644 index 0000000..81e482f --- /dev/null +++ b/benchmarks/benchmarks/espresso/ansi.h @@ -0,0 +1,44 @@ +#ifndef ANSI_H +#define ANSI_H + +/* + * ANSI Compiler Support + * + * David Harrison + * University of California, Berkeley + * 1988 + * + * ANSI compatible compilers are supposed to define the preprocessor + * directive __STDC__. Based on this directive, this file defines + * certain ANSI specific macros. + * + * ARGS: + * Used in function prototypes. Example: + * extern int foo + * ARGS((char *blah, double threshold)); + */ + +/* Function prototypes */ +#if defined(__STDC__) || defined(__cplusplus) +#define ARGS(args) args +#else +#define ARGS(args) () +#endif + +#if defined(__cplusplus) +#define NULLARGS (void) +#else +#define NULLARGS () +#endif + +#ifdef __cplusplus +#define EXTERN extern "C" +#else +#define EXTERN extern +#endif + +#if defined(__cplusplus) || defined(__STDC__) +#define HAS_STDARG +#endif + +#endif diff --git a/benchmarks/benchmarks/espresso/cofactor.c b/benchmarks/benchmarks/espresso/cofactor.c new file mode 100644 index 0000000..e082695 --- /dev/null +++ b/benchmarks/benchmarks/espresso/cofactor.c @@ -0,0 +1,373 @@ +#include "espresso.h" + +/* + The cofactor of a cover against a cube "c" is a cover formed by the + cofactor of each cube in the cover against c. The cofactor of two + cubes is null if they are distance 1 or more apart. If they are + distance zero apart, the cofactor is the restriction of the cube + to the minterms of c. + + The cube list contains the following information: + + T[0] = pointer to a cube identifying the variables that have + been cofactored against + T[1] = pointer to just beyond the sentinel (i.e., T[n] in this case) + T[2] + . + . = pointers to cubes + . + T[n-2] + T[n-1] = NULL pointer (sentinel) + + + Cofactoring involves repeated application of "cdist0" to check if a + cube of the cover intersects the cofactored cube. This can be + slow, especially for the recursive descent of the espresso + routines. Therefore, a special cofactor routine "scofactor" is + provided which assumes the cofactor is only in a single variable. +*/ + + +/* cofactor -- compute the cofactor of a cover with respect to a cube */ +pcube *cofactor(T, c) +IN pcube *T; +IN register pcube c; +{ + pcube temp = cube.temp[0], *Tc_save, *Tc, *T1; + register pcube p; + int listlen; + + listlen = CUBELISTSIZE(T) + 5; + + /* Allocate a new list of cube pointers (max size is previous size) */ + Tc_save = Tc = ALLOC(pcube, listlen); + + /* pass on which variables have been cofactored against */ + *Tc++ = set_or(new_cube(), T[0], set_diff(temp, cube.fullset, c)); + Tc++; + + /* Loop for each cube in the list, determine suitability, and save */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (p != c) { + +#ifdef NO_INLINE + if (! cdist0(p, c)) goto false; +#else + {register int w,last;register unsigned int x;if((last=cube.inword)!=-1) + {x=p[last]&c[last];if(~(x|x>>1)&cube.inmask)goto lfalse;for(w=1;w>1)&DISJOINT)goto lfalse;}}}{register int w,var,last; + register pcube mask;for(var=cube.num_binary_vars;var= 0; i--) + count[i] = 0; + } + + /* Count the number of zeros in each column */ + { register int i, *cnt; + register unsigned int val; + register pcube p, cof = T[0], full = cube.fullset; + for(T1 = T+2; (p = *T1++) != NULL; ) + for(i = LOOP(p); i > 0; i--) + if (val = full[i] & ~ (p[i] | cof[i])) { + cnt = count + ((i-1) << LOGBPI); +#if BPI == 32 + if (val & 0xFF000000) { + if (val & 0x80000000) cnt[31]++; + if (val & 0x40000000) cnt[30]++; + if (val & 0x20000000) cnt[29]++; + if (val & 0x10000000) cnt[28]++; + if (val & 0x08000000) cnt[27]++; + if (val & 0x04000000) cnt[26]++; + if (val & 0x02000000) cnt[25]++; + if (val & 0x01000000) cnt[24]++; + } + if (val & 0x00FF0000) { + if (val & 0x00800000) cnt[23]++; + if (val & 0x00400000) cnt[22]++; + if (val & 0x00200000) cnt[21]++; + if (val & 0x00100000) cnt[20]++; + if (val & 0x00080000) cnt[19]++; + if (val & 0x00040000) cnt[18]++; + if (val & 0x00020000) cnt[17]++; + if (val & 0x00010000) cnt[16]++; + } +#endif + if (val & 0xFF00) { + if (val & 0x8000) cnt[15]++; + if (val & 0x4000) cnt[14]++; + if (val & 0x2000) cnt[13]++; + if (val & 0x1000) cnt[12]++; + if (val & 0x0800) cnt[11]++; + if (val & 0x0400) cnt[10]++; + if (val & 0x0200) cnt[ 9]++; + if (val & 0x0100) cnt[ 8]++; + } + if (val & 0x00FF) { + if (val & 0x0080) cnt[ 7]++; + if (val & 0x0040) cnt[ 6]++; + if (val & 0x0020) cnt[ 5]++; + if (val & 0x0010) cnt[ 4]++; + if (val & 0x0008) cnt[ 3]++; + if (val & 0x0004) cnt[ 2]++; + if (val & 0x0002) cnt[ 1]++; + if (val & 0x0001) cnt[ 0]++; + } + } + } + + /* + * Perform counts for each variable: + * cdata.var_zeros[var] = number of zeros in the variable + * cdata.parts_active[var] = number of active parts for each variable + * cdata.vars_active = number of variables which are active + * cdata.vars_unate = number of variables which are active and unate + * + * best -- the variable which is best for splitting based on: + * mostactive -- most # active parts in any variable + * mostzero -- most # zeros in any variable + * mostbalanced -- minimum over the maximum # zeros / part / variable + */ + + { register int var, i, lastbit, active, maxactive; + int best = -1, mostactive = 0, mostzero = 0, mostbalanced = 32000; + cdata.vars_unate = cdata.vars_active = 0; + + for(var = 0; var < cube.num_vars; var++) { + if (var < cube.num_binary_vars) { /* special hack for binary vars */ + i = count[var*2]; + lastbit = count[var*2 + 1]; + active = (i > 0) + (lastbit > 0); + cdata.var_zeros[var] = i + lastbit; + maxactive = MAX(i, lastbit); + } else { + maxactive = active = cdata.var_zeros[var] = 0; + lastbit = cube.last_part[var]; + for(i = cube.first_part[var]; i <= lastbit; i++) { + cdata.var_zeros[var] += count[i]; + active += (count[i] > 0); + if (active > maxactive) maxactive = active; + } + } + + /* first priority is to maximize the number of active parts */ + /* for binary case, this will usually select the output first */ + if (active > mostactive) + best = var, mostactive = active, mostzero = cdata.var_zeros[best], + mostbalanced = maxactive; + else if (active == mostactive) + /* secondary condition is to maximize the number zeros */ + /* for binary variables, this is the same as minimum # of 2's */ + if (cdata.var_zeros[var] > mostzero) + best = var, mostzero = cdata.var_zeros[best], + mostbalanced = maxactive; + else if (cdata.var_zeros[var] == mostzero) + /* third condition is to pick a balanced variable */ + /* for binary vars, this means roughly equal # 0's and 1's */ + if (maxactive < mostbalanced) + best = var, mostbalanced = maxactive; + + cdata.parts_active[var] = active; + cdata.is_unate[var] = (active == 1); + cdata.vars_active += (active > 0); + cdata.vars_unate += (active == 1); + } + cdata.best = best; + } +} + +int binate_split_select(T, cleft, cright, debug_flag) +IN pcube *T; +IN register pcube cleft, cright; +IN int debug_flag; +{ + int best = cdata.best; + register int i, lastbit = cube.last_part[best], halfbit = 0; + register pcube cof=T[0]; + + /* Create the cubes to cofactor against */ + set_diff(cleft, cube.fullset, cube.var_mask[best]); + set_diff(cright, cube.fullset, cube.var_mask[best]); + for(i = cube.first_part[best]; i <= lastbit; i++) + if (! is_in_set(cof,i)) + halfbit++; + for(i = cube.first_part[best], halfbit = halfbit/2; halfbit > 0; i++) + if (! is_in_set(cof,i)) + halfbit--, set_insert(cleft, i); + for(; i <= lastbit; i++) + if (! is_in_set(cof,i)) + set_insert(cright, i); + + if (debug & debug_flag) { + printf("BINATE_SPLIT_SELECT: split against %d\n", best); + if (verbose_debug) + printf("cl=%s\ncr=%s\n", pc1(cleft), pc2(cright)); + } + return best; +} + + +pcube *cube1list(A) +pcover A; +{ + register pcube last, p, *plist, *list; + + list = plist = ALLOC(pcube, A->count + 3); + *plist++ = new_cube(); + plist++; + foreach_set(A, last, p) { + *plist++ = p; + } + *plist++ = NULL; /* sentinel */ + list[1] = (pcube) plist; + return list; +} + + +pcube *cube2list(A, B) +pcover A, B; +{ + register pcube last, p, *plist, *list; + + list = plist = ALLOC(pcube, A->count + B->count + 3); + *plist++ = new_cube(); + plist++; + foreach_set(A, last, p) { + *plist++ = p; + } + foreach_set(B, last, p) { + *plist++ = p; + } + *plist++ = NULL; + list[1] = (pcube) plist; + return list; +} + + +pcube *cube3list(A, B, C) +pcover A, B, C; +{ + register pcube last, p, *plist, *list; + + plist = ALLOC(pcube, A->count + B->count + C->count + 3); + list = plist; + *plist++ = new_cube(); + plist++; + foreach_set(A, last, p) { + *plist++ = p; + } + foreach_set(B, last, p) { + *plist++ = p; + } + foreach_set(C, last, p) { + *plist++ = p; + } + *plist++ = NULL; + list[1] = (pcube) plist; + return list; +} + + +pcover cubeunlist(A1) +pcube *A1; +{ + register int i; + register pcube p, pdest, cof = A1[0]; + register pcover A; + + A = new_cover(CUBELISTSIZE(A1)); + for(i = 2; (p = A1[i]) != NULL; i++) { + pdest = GETSET(A, i-2); + INLINEset_or(pdest, p, cof); + } + A->count = CUBELISTSIZE(A1); + return A; +} + +simplify_cubelist(T) +pcube *T; +{ + register pcube *Tdest; + register int i, ncubes; + + set_copy(cube.temp[0], T[0]); /* retrieve cofactor */ + + ncubes = CUBELISTSIZE(T); + qsort((char *) (T+2), ncubes, sizeof(pset), d1_order); + + Tdest = T+2; + /* *Tdest++ = T[2]; */ + for(i = 3; i < ncubes; i++) { + if (d1_order(&T[i-1], &T[i]) != 0) { + *Tdest++ = T[i]; + } + } + + *Tdest++ = NULL; /* sentinel */ + Tdest[1] = (pcube) Tdest; /* save pointer to last */ +} diff --git a/benchmarks/benchmarks/espresso/cols.c b/benchmarks/benchmarks/espresso/cols.c new file mode 100644 index 0000000..0bfa160 --- /dev/null +++ b/benchmarks/benchmarks/espresso/cols.c @@ -0,0 +1,306 @@ +#include "espresso.h" +#include "port.h" +#include "sparse_int.h" + + +/* + * allocate a new col vector + */ +sm_col * +sm_col_alloc() +{ + register sm_col *pcol; + +#ifdef FAST_AND_LOOSE + if (sm_col_freelist == NIL(sm_col)) { + pcol = ALLOC(sm_col, 1); + } else { + pcol = sm_col_freelist; + sm_col_freelist = pcol->next_col; + } +#else + pcol = ALLOC(sm_col, 1); +#endif + + pcol->col_num = 0; + pcol->length = 0; + pcol->first_row = pcol->last_row = NIL(sm_element); + pcol->next_col = pcol->prev_col = NIL(sm_col); + pcol->flag = 0; + pcol->user_word = NIL(char); /* for our user ... */ + return pcol; +} + + +/* + * free a col vector -- for FAST_AND_LOOSE, this is real cheap for cols; + * however, freeing a rowumn must still walk down the rowumn discarding + * the elements one-by-one; that is the only use for the extra '-DCOLS' + * compile flag ... + */ +void +sm_col_free(pcol) +register sm_col *pcol; +{ +#if defined(FAST_AND_LOOSE) && ! defined(COLS) + if (pcol->first_row != NIL(sm_element)) { + /* Add the linked list of col items to the free list */ + pcol->last_row->next_row = sm_element_freelist; + sm_element_freelist = pcol->first_row; + } + + /* Add the col to the free list of cols */ + pcol->next_col = sm_col_freelist; + sm_col_freelist = pcol; +#else + register sm_element *p, *pnext; + + for(p = pcol->first_row; p != 0; p = pnext) { + pnext = p->next_row; + sm_element_free(p); + } + FREE(pcol); +#endif +} + + +/* + * duplicate an existing col + */ +sm_col * +sm_col_dup(pcol) +register sm_col *pcol; +{ + register sm_col *pnew; + register sm_element *p; + + pnew = sm_col_alloc(); + for(p = pcol->first_row; p != 0; p = p->next_row) { + (void) sm_col_insert(pnew, p->row_num); + } + return pnew; +} + + +/* + * insert an element into a col vector + */ +sm_element * +sm_col_insert(pcol, row) +register sm_col *pcol; +register int row; +{ + register sm_element *test, *element; + + /* get a new item, save its address */ + sm_element_alloc(element); + test = element; + sorted_insert(sm_element, pcol->first_row, pcol->last_row, pcol->length, + next_row, prev_row, row_num, row, test); + + /* if item was not used, free it */ + if (element != test) { + sm_element_free(element); + } + + /* either way, return the current new value */ + return test; +} + + +/* + * remove an element from a col vector + */ +void +sm_col_remove(pcol, row) +register sm_col *pcol; +register int row; +{ + register sm_element *p; + + for(p = pcol->first_row; p != 0 && p->row_num < row; p = p->next_row) + ; + if (p != 0 && p->row_num == row) { + dll_unlink(p, pcol->first_row, pcol->last_row, + next_row, prev_row, pcol->length); + sm_element_free(p); + } +} + + +/* + * find an element (if it is in the col vector) + */ +sm_element * +sm_col_find(pcol, row) +sm_col *pcol; +int row; +{ + register sm_element *p; + + for(p = pcol->first_row; p != 0 && p->row_num < row; p = p->next_row) + ; + if (p != 0 && p->row_num == row) { + return p; + } else { + return NIL(sm_element); + } +} + +/* + * return 1 if col p2 contains col p1; 0 otherwise + */ +int +sm_col_contains(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_row; + q2 = p2->first_row; + while (q1 != 0) { + if (q2 == 0 || q1->row_num < q2->row_num) { + return 0; + } else if (q1->row_num == q2->row_num) { + q1 = q1->next_row; + q2 = q2->next_row; + } else { + q2 = q2->next_row; + } + } + return 1; +} + + +/* + * return 1 if col p1 and col p2 share an element in common + */ +int +sm_col_intersects(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_row; + q2 = p2->first_row; + if (q1 == 0 || q2 == 0) return 0; + for(;;) { + if (q1->row_num < q2->row_num) { + if ((q1 = q1->next_row) == 0) { + return 0; + } + } else if (q1->row_num > q2->row_num) { + if ((q2 = q2->next_row) == 0) { + return 0; + } + } else { + return 1; + } + } +} + + +/* + * compare two cols, lexical ordering + */ +int +sm_col_compare(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_row; + q2 = p2->first_row; + while(q1 != 0 && q2 != 0) { + if (q1->row_num != q2->row_num) { + return q1->row_num - q2->row_num; + } + q1 = q1->next_row; + q2 = q2->next_row; + } + + if (q1 != 0) { + return 1; + } else if (q2 != 0) { + return -1; + } else { + return 0; + } +} + + +/* + * return the intersection + */ +sm_col * +sm_col_and(p1, p2) +sm_col *p1, *p2; +{ + register sm_element *q1, *q2; + register sm_col *result; + + result = sm_col_alloc(); + q1 = p1->first_row; + q2 = p2->first_row; + if (q1 == 0 || q2 == 0) return result; + for(;;) { + if (q1->row_num < q2->row_num) { + if ((q1 = q1->next_row) == 0) { + return result; + } + } else if (q1->row_num > q2->row_num) { + if ((q2 = q2->next_row) == 0) { + return result; + } + } else { + (void) sm_col_insert(result, q1->row_num); + if ((q1 = q1->next_row) == 0) { + return result; + } + if ((q2 = q2->next_row) == 0) { + return result; + } + } + } +} + +int +sm_col_hash(pcol, modulus) +sm_col *pcol; +int modulus; +{ + register int sum; + register sm_element *p; + + sum = 0; + for(p = pcol->first_row; p != 0; p = p->next_row) { + sum = (sum*17 + p->row_num) % modulus; + } + return sum; +} + +/* + * remove an element from a col vector (given a pointer to the element) + */ +void +sm_col_remove_element(pcol, p) +register sm_col *pcol; +register sm_element *p; +{ + dll_unlink(p, pcol->first_row, pcol->last_row, + next_row, prev_row, pcol->length); + sm_element_free(p); +} + + +void +sm_col_print(fp, pcol) +FILE *fp; +sm_col *pcol; +{ + sm_element *p; + + for(p = pcol->first_row; p != 0; p = p->next_row) { + (void) fprintf(fp, " %d", p->row_num); + } +} diff --git a/benchmarks/benchmarks/espresso/compl.c b/benchmarks/benchmarks/espresso/compl.c new file mode 100644 index 0000000..d0db019 --- /dev/null +++ b/benchmarks/benchmarks/espresso/compl.c @@ -0,0 +1,667 @@ +/* + * module: compl.c + * purpose: compute the complement of a multiple-valued function + * + * The "unate recursive paradigm" is used. After a set of special + * cases are examined, the function is split on the "most active + * variable". These two halves are complemented recursively, and then + * the results are merged. + * + * Changes (from Version 2.1 to Version 2.2) + * 1. Minor bug in compl_lifting -- cubes in the left half were + * not marked as active, so that when merging a leaf from the left + * hand side, the active flags were essentially random. This led + * to minor impredictability problem, but never affected the + * accuracy of the results. + */ + +#include "espresso.h" + +#define USE_COMPL_LIFT 0 +#define USE_COMPL_LIFT_ONSET 1 +#define USE_COMPL_LIFT_ONSET_COMPLEX 2 +#define NO_LIFTING 3 + +static bool compl_special_cases(); +static pcover compl_merge(); +static void compl_d1merge(); +static pcover compl_cube(); +static void compl_lift(); +static void compl_lift_onset(); +static void compl_lift_onset_complex(); +static bool simp_comp_special_cases(); +static bool simplify_special_cases(); + + +/* complement -- compute the complement of T */ +pcover complement(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best; + pcover Tbar, Tl, Tr; + int lifting; + static int compl_level = 0; + + if (debug & COMPL) + debug_print(T, "COMPLEMENT", compl_level++); + + if (compl_special_cases(T, &Tbar) == MAYBE) { + + /* Allocate space for the partition cubes */ + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, COMPL); + + /* Complement the left and right halves */ + Tl = complement(scofactor(T, cl, best)); + Tr = complement(scofactor(T, cr, best)); + + if (Tr->count*Tl->count > (Tr->count+Tl->count)*CUBELISTSIZE(T)) { + lifting = USE_COMPL_LIFT_ONSET; + } else { + lifting = USE_COMPL_LIFT; + } + Tbar = compl_merge(T, Tl, Tr, cl, cr, best, lifting); + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + if (debug & COMPL) + debug1_print(Tbar, "exit COMPLEMENT", --compl_level); + return Tbar; +} + +static bool compl_special_cases(T, Tbar) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tbar; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcover A, ceil_compl; + + /* Check for no cubes in the cover */ + if (T[2] == NULL) { + *Tbar = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + *Tbar = compl_cube(set_or(cof, cof, T[2])); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (implies complement is null) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tbar = new_cover(0); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + ceil_compl = compl_cube(ceil); + (void) set_or(cof, cof, set_diff(ceil, cube.fullset, ceil)); + set_free(ceil); + *Tbar = sf_append(complement(T), ceil_compl); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tbar = new_cover(0); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + A = map_cover_to_unate(T); + free_cubelist(T); + A = unate_compl(A); + *Tbar = map_unate_to_cover(A); + sf_free(A); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} + +/* + * compl_merge -- merge the two cofactors around the splitting + * variable + * + * The merge operation involves intersecting each cube of the left + * cofactor with cl, and intersecting each cube of the right cofactor + * with cr. The union of these two covers is the merged result. + * + * In order to reduce the number of cubes, a distance-1 merge is + * performed (note that two cubes can only combine distance-1 in the + * splitting variable). Also, a simple expand is performed in the + * splitting variable (simple implies the covering check for the + * expansion is not full containment, but single-cube containment). + */ + +static pcover compl_merge(T1, L, R, cl, cr, var, lifting) +pcube *T1; /* Original ON-set */ +pcover L, R; /* Complement from each recursion branch */ +register pcube cl, cr; /* cubes used for cofactoring */ +int var; /* splitting variable */ +int lifting; /* whether to perform lifting or not */ +{ + register pcube p, last, pt; + pcover T, Tbar; + pcube *L1, *R1; + + if (debug & COMPL) { + printf("compl_merge: left %d, right %d\n", L->count, R->count); + printf("%s (cl)\n%s (cr)\nLeft is\n", pc1(cl), pc2(cr)); + cprint(L); + printf("Right is\n"); + cprint(R); + } + + /* Intersect each cube with the cofactored cube */ + foreach_set(L, last, p) { + INLINEset_and(p, p, cl); + SET(p, ACTIVE); + } + foreach_set(R, last, p) { + INLINEset_and(p, p, cr); + SET(p, ACTIVE); + } + + /* Sort the arrays for a distance-1 merge */ + (void) set_copy(cube.temp[0], cube.var_mask[var]); + qsort((char *) (L1 = sf_list(L)), L->count, sizeof(pset), d1_order); + qsort((char *) (R1 = sf_list(R)), R->count, sizeof(pset), d1_order); + + /* Perform distance-1 merge */ + compl_d1merge(L1, R1); + + /* Perform lifting */ + switch(lifting) { + case USE_COMPL_LIFT_ONSET: + T = cubeunlist(T1); + compl_lift_onset(L1, T, cr, var); + compl_lift_onset(R1, T, cl, var); + free_cover(T); + break; + case USE_COMPL_LIFT_ONSET_COMPLEX: + T = cubeunlist(T1); + compl_lift_onset_complex(L1, T, var); + compl_lift_onset_complex(R1, T, var); + free_cover(T); + break; + case USE_COMPL_LIFT: + compl_lift(L1, R1, cr, var); + compl_lift(R1, L1, cl, var); + break; + case NO_LIFTING: + break; + } + FREE(L1); + FREE(R1); + + /* Re-create the merged cover */ + Tbar = new_cover(L->count + R->count); + pt = Tbar->data; + foreach_set(L, last, p) { + INLINEset_copy(pt, p); + Tbar->count++; + pt += Tbar->wsize; + } + foreach_active_set(R, last, p) { + INLINEset_copy(pt, p); + Tbar->count++; + pt += Tbar->wsize; + } + + if (debug & COMPL) { + printf("Result %d\n", Tbar->count); + if (verbose_debug) + cprint(Tbar); + } + + free_cover(L); + free_cover(R); + return Tbar; +} + +/* + * compl_lift_simple -- expand in the splitting variable using single + * cube containment against the other recursion branch to check + * validity of the expansion, and expanding all (or none) of the + * splitting variable. + */ +static void compl_lift(A1, B1, bcube, var) +pcube *A1, *B1, bcube; +int var; +{ + register pcube a, b, *B2, lift=cube.temp[4], liftor=cube.temp[5]; + pcube mask = cube.var_mask[var]; + + (void) set_and(liftor, bcube, mask); + + /* for each cube in the first array ... */ + for(; (a = *A1++) != NULL; ) { + if (TESTP(a, ACTIVE)) { + + /* create a lift of this cube in the merging coord */ + (void) set_merge(lift, bcube, a, mask); + + /* for each cube in the second array */ + for(B2 = B1; (b = *B2++) != NULL; ) { + INLINEsetp_implies(lift, b, /* when_false => */ continue); + /* when_true => fall through to next statement */ + + /* cube of A1 was contained by some cube of B1, so raise */ + INLINEset_or(a, a, liftor); + break; + } + } + } +} + + + +/* + * compl_lift_onset -- expand in the splitting variable using a + * distance-1 check against the original on-set; expand all (or + * none) of the splitting variable. Each cube of A1 is expanded + * against the original on-set T. + */ +static void compl_lift_onset(A1, T, bcube, var) +pcube *A1; +pcover T; +pcube bcube; +int var; +{ + register pcube a, last, p, lift=cube.temp[4], mask=cube.var_mask[var]; + + /* for each active cube from one branch of the complement */ + for(; (a = *A1++) != NULL; ) { + if (TESTP(a, ACTIVE)) { + + /* create a lift of this cube in the merging coord */ + INLINEset_and(lift, bcube, mask); /* isolate parts to raise */ + INLINEset_or(lift, a, lift); /* raise these parts in a */ + + /* for each cube in the ON-set, check for intersection */ + foreach_set(T, last, p) { + if (cdist0(p, lift)) { + goto nolift; + } + } + INLINEset_copy(a, lift); /* save the raising */ + SET(a, ACTIVE); +nolift : ; + } + } +} + +/* + * compl_lift_complex -- expand in the splitting variable, but expand all + * parts which can possibly expand. + * T is the original ON-set + * A1 is either the left or right cofactor + */ +static void compl_lift_onset_complex(A1, T, var) +pcube *A1; /* array of pointers to new result */ +pcover T; /* original ON-set */ +int var; /* which variable we split on */ +{ + register int dist; + register pcube last, p, a, xlower; + + /* for each cube in the complement */ + xlower = new_cube(); + for(; (a = *A1++) != NULL; ) { + + if (TESTP(a, ACTIVE)) { + + /* Find which parts of the splitting variable are forced low */ + INLINEset_clear(xlower, cube.size); + foreach_set(T, last, p) { + if ((dist = cdist01(p, a)) < 2) { + if (dist == 0) { + fatal("compl: ON-set and OFF-set are not orthogonal"); + } else { + (void) force_lower(xlower, p, a); + } + } + } + + (void) set_diff(xlower, cube.var_mask[var], xlower); + (void) set_or(a, a, xlower); + free_cube(xlower); + } + } +} + + + +/* + * compl_d1merge -- distance-1 merge in the splitting variable + */ +static void compl_d1merge(L1, R1) +register pcube *L1, *R1; +{ + register pcube pl, pr; + + /* Find equal cubes between the two cofactors */ + for(pl = *L1, pr = *R1; (pl != NULL) && (pr != NULL); ) + switch (d1_order(L1, R1)) { + case 1: + pr = *(++R1); break; /* advance right pointer */ + case -1: + pl = *(++L1); break; /* advance left pointer */ + case 0: + RESET(pr, ACTIVE); + INLINEset_or(pl, pl, pr); + pr = *(++R1); + } +} + + + +/* compl_cube -- return the complement of a single cube (De Morgan's law) */ +static pcover compl_cube(p) +register pcube p; +{ + register pcube diff=cube.temp[7], pdest, mask, full=cube.fullset; + int var; + pcover R; + + /* Allocate worst-case size cover (to avoid checking overflow) */ + R = new_cover(cube.num_vars); + + /* Compute bit-wise complement of the cube */ + INLINEset_diff(diff, full, p); + + for(var = 0; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; + /* If the bit-wise complement is not empty in var ... */ + if (! setp_disjoint(diff, mask)) { + pdest = GETSET(R, R->count++); + INLINEset_merge(pdest, diff, full, mask); + } + } + return R; +} + +/* simp_comp -- quick simplification of T */ +void simp_comp(T, Tnew, Tbar) +pcube *T; /* T will be disposed of */ +pcover *Tnew; +pcover *Tbar; +{ + register pcube cl, cr; + register int best; + pcover Tl, Tr, Tlbar, Trbar; + int lifting; + static int simplify_level = 0; + + if (debug & COMPL) + debug_print(T, "SIMPCOMP", simplify_level++); + + if (simp_comp_special_cases(T, Tnew, Tbar) == MAYBE) { + + /* Allocate space for the partition cubes */ + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, COMPL); + + /* Complement the left and right halves */ + simp_comp(scofactor(T, cl, best), &Tl, &Tlbar); + simp_comp(scofactor(T, cr, best), &Tr, &Trbar); + + lifting = USE_COMPL_LIFT; + *Tnew = compl_merge(T, Tl, Tr, cl, cr, best, lifting); + + lifting = USE_COMPL_LIFT; + *Tbar = compl_merge(T, Tlbar, Trbar, cl, cr, best, lifting); + + /* All of this work for nothing ? Let's hope not ... */ + if ((*Tnew)->count > CUBELISTSIZE(T)) { + sf_free(*Tnew); + *Tnew = cubeunlist(T); + } + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + if (debug & COMPL) { + debug1_print(*Tnew, "exit SIMPCOMP (new)", simplify_level); + debug1_print(*Tbar, "exit SIMPCOMP (compl)", simplify_level); + simplify_level--; + } +} + +static bool simp_comp_special_cases(T, Tnew, Tbar) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tnew; /* returned only if answer determined */ +pcover *Tbar; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcube last; + pcover A; + + /* Check for no cubes in the cover (function is empty) */ + if (T[2] == NULL) { + *Tnew = new_cover(1); + *Tbar = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + (void) set_or(cof, cof, T[2]); + *Tnew = sf_addset(new_cover(1), cof); + *Tbar = compl_cube(cof); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (function is a tautology) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + *Tbar = new_cover(1); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + p = new_cube(); + (void) set_diff(p, cube.fullset, ceil); + (void) set_or(cof, cof, p); + set_free(p); + simp_comp(T, Tnew, Tbar); + + /* Adjust the ON-set */ + A = *Tnew; + foreach_set(A, last, p) { + INLINEset_and(p, p, ceil); + } + + /* Compute the new complement */ + *Tbar = sf_append(*Tbar, compl_cube(ceil)); + set_free(ceil); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + *Tbar = new_cover(1); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + /* Make the cover minimum by single-cube containment */ + A = cubeunlist(T); + *Tnew = sf_contain(A); + + /* Now form a minimum representation of the complement */ + A = map_cover_to_unate(T); + A = unate_compl(A); + *Tbar = map_unate_to_cover(A); + sf_free(A); + free_cubelist(T); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} + +/* simplify -- quick simplification of T */ +pcover simplify(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best; + pcover Tbar, Tl, Tr; + int lifting; + static int simplify_level = 0; + + if (debug & COMPL) { + debug_print(T, "SIMPLIFY", simplify_level++); + } + + if (simplify_special_cases(T, &Tbar) == MAYBE) { + + /* Allocate space for the partition cubes */ + cl = new_cube(); + cr = new_cube(); + + best = binate_split_select(T, cl, cr, COMPL); + + /* Complement the left and right halves */ + Tl = simplify(scofactor(T, cl, best)); + Tr = simplify(scofactor(T, cr, best)); + + lifting = USE_COMPL_LIFT; + Tbar = compl_merge(T, Tl, Tr, cl, cr, best, lifting); + + /* All of this work for nothing ? Let's hope not ... */ + if (Tbar->count > CUBELISTSIZE(T)) { + sf_free(Tbar); + Tbar = cubeunlist(T); + } + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + if (debug & COMPL) { + debug1_print(Tbar, "exit SIMPLIFY", --simplify_level); + } + return Tbar; +} + +static bool simplify_special_cases(T, Tnew) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tnew; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcube last; + pcover A; + + /* Check for no cubes in the cover */ + if (T[2] == NULL) { + *Tnew = new_cover(0); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + *Tnew = sf_addset(new_cover(1), set_or(cof, cof, T[2])); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (implies function is a tautology) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + p = new_cube(); + (void) set_diff(p, cube.fullset, ceil); + (void) set_or(cof, cof, p); + free_cube(p); + + A = simplify(T); + foreach_set(A, last, p) { + INLINEset_and(p, p, ceil); + } + *Tnew = A; + set_free(ceil); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + A = cubeunlist(T); + *Tnew = sf_contain(A); + free_cubelist(T); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} diff --git a/benchmarks/benchmarks/espresso/contain.c b/benchmarks/benchmarks/espresso/contain.c new file mode 100644 index 0000000..6b9c644 --- /dev/null +++ b/benchmarks/benchmarks/espresso/contain.c @@ -0,0 +1,432 @@ +/* + contain.c -- set containment routines + + These are complex routines for performing containment over a + family of sets, but they have the advantage of being much faster + than a straightforward n*n routine. + + First the cubes are sorted by size, and as a secondary key they are + sorted so that if two cubes are equal they end up adjacent. We can + than quickly remove equal cubes from further consideration by + comparing each cube to its neighbor. Finally, because the cubes + are sorted by size, we need only check cubes which are larger (or + smaller) than a given cube for containment. +*/ + +#include "espresso.h" + + +/* + sf_contain -- perform containment on a set family (delete sets which + are contained by some larger set in the family). No assumptions are + made about A, and the result will be returned in decreasing order of + set size. +*/ +pset_family sf_contain(A) +INOUT pset_family A; /* disposes of A */ +{ + int cnt; + pset *A1; + pset_family R; + + A1 = sf_sort(A, descend); /* sort into descending order */ + cnt = rm_equal(A1, descend); /* remove duplicates */ + cnt = rm_contain(A1); /* remove contained sets */ + R = sf_unlist(A1, cnt, A->sf_size); /* recreate the set family */ + sf_free(A); + return R; +} + + +/* + sf_rev_contain -- perform containment on a set family (delete sets which + contain some smaller set in the family). No assumptions are made about + A, and the result will be returned in increasing order of set size +*/ +pset_family sf_rev_contain(A) +INOUT pset_family A; /* disposes of A */ +{ + int cnt; + pset *A1; + pset_family R; + + A1 = sf_sort(A, ascend); /* sort into ascending order */ + cnt = rm_equal(A1, ascend); /* remove duplicates */ + cnt = rm_rev_contain(A1); /* remove containing sets */ + R = sf_unlist(A1, cnt, A->sf_size); /* recreate the set family */ + sf_free(A); + return R; +} + + +/* + sf_ind_contain -- perform containment on a set family (delete sets which + are contained by some larger set in the family). No assumptions are + made about A, and the result will be returned in decreasing order of + set size. Also maintains a set of row_indices to track which rows + disappear and how the rows end up permuted. +*/ +pset_family sf_ind_contain(A, row_indices) +INOUT pset_family A; /* disposes of A */ +INOUT int *row_indices; /* updated with the new values */ +{ + int cnt; + pset *A1; + pset_family R; + + A1 = sf_sort(A, descend); /* sort into descending order */ + cnt = rm_equal(A1, descend); /* remove duplicates */ + cnt = rm_contain(A1); /* remove contained sets */ + R = sf_ind_unlist(A1, cnt, A->sf_size, row_indices, A->data); + sf_free(A); + return R; +} + + +/* sf_dupl -- delete duplicate sets in a set family */ +pset_family sf_dupl(A) +INOUT pset_family A; /* disposes of A */ +{ + register int cnt; + register pset *A1; + pset_family R; + + A1 = sf_sort(A, descend); /* sort the set family */ + cnt = rm_equal(A1, descend); /* remove duplicates */ + R = sf_unlist(A1, cnt, A->sf_size); /* recreate the set family */ + sf_free(A); + return R; +} + + +/* + sf_union -- form the contained union of two set families (delete + sets which are contained by some larger set in the family). A and + B are assumed already sorted in decreasing order of set size (and + the SIZE field is assumed to contain the set size), and the result + will be returned sorted likewise. +*/ +pset_family sf_union(A, B) +INOUT pset_family A, B; /* disposes of A and B */ +{ + int cnt; + pset_family R; + pset *A1 = sf_list(A), *B1 = sf_list(B), *E1; + + E1 = ALLOC(pset, MAX(A->count, B->count) + 1); + cnt = rm2_equal(A1, B1, E1, descend); + cnt += rm2_contain(A1, B1) + rm2_contain(B1, A1); + R = sf_merge(A1, B1, E1, cnt, A->sf_size); + sf_free(A); sf_free(B); + return R; +} + + +/* + dist_merge -- consider all sets to be "or"-ed with "mask" and then + delete duplicates from the set family. +*/ +pset_family dist_merge(A, mask) +INOUT pset_family A; /* disposes of A */ +IN pset mask; /* defines variables to mask out */ +{ + pset *A1; + int cnt; + pset_family R; + + set_copy(cube.temp[0], mask); + A1 = sf_sort(A, d1_order); + cnt = d1_rm_equal(A1, d1_order); + R = sf_unlist(A1, cnt, A->sf_size); + sf_free(A); + return R; +} + + +/* + d1merge -- perform an efficient distance-1 merge of cubes of A +*/ +pset_family d1merge(A, var) +INOUT pset_family A; /* disposes of A */ +IN int var; +{ + return dist_merge(A, cube.var_mask[var]); +} + + + +/* d1_rm_equal -- distance-1 merge (merge cubes which are equal under a mask) */ +int d1_rm_equal(A1, compare) +register pset *A1; /* array of set pointers */ +int (*compare)(); /* comparison function */ +{ + register int i, j, dest; + + dest = 0; + if (A1[0] != (pcube) NULL) { + for(i = 0, j = 1; A1[j] != (pcube) NULL; j++) + if ( (*compare)(&A1[i], &A1[j]) == 0) { + /* if sets are equal (under the mask) merge them */ + set_or(A1[i], A1[i], A1[j]); + } else { + /* sets are unequal, so save the set i */ + A1[dest++] = A1[i]; + i = j; + } + A1[dest++] = A1[i]; + } + A1[dest] = (pcube) NULL; + return dest; +} + + +/* rm_equal -- scan a sorted array of set pointers for duplicate sets */ +int rm_equal(A1, compare) +INOUT pset *A1; /* updated in place */ +IN int (*compare)(); +{ + register pset *p, *pdest = A1; + + if (*A1 != NULL) { /* If more than one set */ + for(p = A1+1; *p != NULL; p++) + if ((*compare)(p, p-1) != 0) + *pdest++ = *(p-1); + *pdest++ = *(p-1); + *pdest = NULL; + } + return pdest - A1; +} + + +/* rm_contain -- perform containment over a sorted array of set pointers */ +int rm_contain(A1) +INOUT pset *A1; /* updated in place */ +{ + register pset *pa, *pb, *pcheck, a, b; + pset *pdest = A1; + int last_size = -1; + + /* Loop for all cubes of A1 */ + for(pa = A1; (a = *pa++) != NULL; ) { + /* Update the check pointer if the size has changed */ + if (SIZE(a) != last_size) + last_size = SIZE(a), pcheck = pdest; + for(pb = A1; pb != pcheck; ) { + b = *pb++; + INLINEsetp_implies(a, b, /* when_false => */ continue); + goto lnext1; + } + /* set a was not contained by some larger set, so save it */ + *pdest++ = a; + lnext1: ; + } + + *pdest = NULL; + return pdest - A1; +} + + +/* rm_rev_contain -- perform rcontainment over a sorted array of set pointers */ +int rm_rev_contain(A1) +INOUT pset *A1; /* updated in place */ +{ + register pset *pa, *pb, *pcheck, a, b; + pset *pdest = A1; + int last_size = -1; + + /* Loop for all cubes of A1 */ + for(pa = A1; (a = *pa++) != NULL; ) { + /* Update the check pointer if the size has changed */ + if (SIZE(a) != last_size) + last_size = SIZE(a), pcheck = pdest; + for(pb = A1; pb != pcheck; ) { + b = *pb++; + INLINEsetp_implies(b, a, /* when_false => */ continue); + goto lnext1; + } + /* the set a did not contain some smaller set, so save it */ + *pdest++ = a; + lnext1: ; + } + + *pdest = NULL; + return pdest - A1; +} + + +/* rm2_equal -- check two sorted arrays of set pointers for equal cubes */ +int rm2_equal(A1, B1, E1, compare) +INOUT register pset *A1, *B1; /* updated in place */ +OUT pset *E1; +IN int (*compare)(); +{ + register pset *pda = A1, *pdb = B1, *pde = E1; + + /* Walk through the arrays advancing pointer to larger cube */ + for(; *A1 != NULL && *B1 != NULL; ) + switch((*compare)(A1, B1)) { + case -1: /* "a" comes before "b" */ + *pda++ = *A1++; break; + case 0: /* equal cubes */ + *pde++ = *A1++; B1++; break; + case 1: /* "a" is to follow "b" */ + *pdb++ = *B1++; break; + } + + /* Finish moving down the pointers of A and B */ + while (*A1 != NULL) + *pda++ = *A1++; + while (*B1 != NULL) + *pdb++ = *B1++; + *pda = *pdb = *pde = NULL; + + return pde - E1; +} + + +/* rm2_contain -- perform containment between two arrays of set pointers */ +int rm2_contain(A1, B1) +INOUT pset *A1; /* updated in place */ +IN pset *B1; /* unchanged */ +{ + register pset *pa, *pb, a, b, *pdest = A1; + + /* for each set in the first array ... */ + for(pa = A1; (a = *pa++) != NULL; ) { + /* for each set in the second array which is larger ... */ + for(pb = B1; (b = *pb++) != NULL && SIZE(b) > SIZE(a); ) { + INLINEsetp_implies(a, b, /* when_false => */ continue); + /* set was contained in some set of B, so don't save pointer */ + goto lnext1; + } + /* set wasn't contained in any set of B, so save the pointer */ + *pdest++ = a; + lnext1: ; + } + + *pdest = NULL; /* sentinel */ + return pdest - A1; /* # elements in A1 */ +} + + + +/* sf_sort -- sort the sets of A */ +pset *sf_sort(A, compare) +IN pset_family A; +IN int (*compare)(); +{ + register pset p, last, *pdest, *A1; + + /* Create a single array pointing to each cube of A */ + pdest = A1 = ALLOC(pset, A->count + 1); + foreach_set(A, last, p) { + PUTSIZE(p, set_ord(p)); /* compute the set size */ + *pdest++ = p; /* save the pointer */ + } + *pdest = NULL; /* Sentinel -- never seen by sort */ + + /* Sort cubes by size */ + qsort((char *) A1, A->count, sizeof(pset), compare); + return A1; +} + + +/* sf_list -- make a list of pointers to the sets in a set family */ +pset *sf_list(A) +IN register pset_family A; +{ + register pset p, last, *pdest, *A1; + + /* Create a single array pointing to each cube of A */ + pdest = A1 = ALLOC(pset, A->count + 1); + foreach_set(A, last, p) + *pdest++ = p; /* save the pointer */ + *pdest = NULL; /* Sentinel */ + return A1; +} + + +/* sf_unlist -- make a set family out of a list of pointers to sets */ +pset_family sf_unlist(A1, totcnt, size) +IN pset *A1; +IN int totcnt, size; +{ + register pset pr, p, *pa; + pset_family R = sf_new(totcnt, size); + + R->count = totcnt; + for(pr = R->data, pa = A1; (p = *pa++) != NULL; pr += R->wsize) + INLINEset_copy(pr, p); + FREE(A1); + return R; +} + + +/* sf_ind_unlist -- make a set family out of a list of pointers to sets */ +pset_family sf_ind_unlist(A1, totcnt, size, row_indices, pfirst) +IN pset *A1; +IN int totcnt, size; +INOUT int *row_indices; +IN register pset pfirst; +{ + register pset pr, p, *pa; + register int i, *new_row_indices; + pset_family R = sf_new(totcnt, size); + + R->count = totcnt; + new_row_indices = ALLOC(int, totcnt); + for(pr = R->data, pa = A1, i=0; (p = *pa++) != NULL; pr += R->wsize, i++) { + INLINEset_copy(pr, p); + new_row_indices[i] = row_indices[(p - pfirst)/R->wsize]; + } + for(i = 0; i < totcnt; i++) + row_indices[i] = new_row_indices[i]; + FREE(new_row_indices); + FREE(A1); + return R; +} + + +/* sf_merge -- merge three sorted lists of set pointers */ +pset_family sf_merge(A1, B1, E1, totcnt, size) +INOUT pset *A1, *B1, *E1; /* will be disposed of */ +IN int totcnt, size; +{ + register pset pr, ps, *pmin, *pmid, *pmax; + pset_family R; + pset *temp[3], *swap; + int i, j, n; + + /* Allocate the result set_family */ + R = sf_new(totcnt, size); + R->count = totcnt; + pr = R->data; + + /* Quick bubble sort to order the top member of the three arrays */ + n = 3; temp[0] = A1; temp[1] = B1; temp[2] = E1; + for(i = 0; i < n-1; i++) + for(j = i+1; j < n; j++) + if (desc1(*temp[i], *temp[j]) > 0) { + swap = temp[j]; + temp[j] = temp[i]; + temp[i] = swap; + } + pmin = temp[0]; pmid = temp[1]; pmax = temp[2]; + + /* Save the minimum element, then update pmin, pmid, pmax */ + while (*pmin != (pset) NULL) { + ps = *pmin++; + INLINEset_copy(pr, ps); + pr += R->wsize; + if (desc1(*pmin, *pmax) > 0) { + swap = pmax; pmax = pmin; pmin = pmid; pmid = swap; + } else if (desc1(*pmin, *pmid) > 0) { + swap = pmin; pmin = pmid; pmid = swap; + } + } + + FREE(A1); + FREE(B1); + FREE(E1); + return R; +} diff --git a/benchmarks/benchmarks/espresso/copyright.h b/benchmarks/benchmarks/espresso/copyright.h new file mode 100644 index 0000000..49c2f0b --- /dev/null +++ b/benchmarks/benchmarks/espresso/copyright.h @@ -0,0 +1,29 @@ +#ifndef OCTTOOLS_COPYRIGHT_H +#define OCTTOOLS_COPYRIGHT_H +/* + * Oct Tools Distribution 4.0 + * + * Copyright (c) 1988, 1989, 1990, Regents of the University of California. + * All rights reserved. + * + * Use and copying of this software and preparation of derivative works + * based upon this software are permitted. However, any distribution of + * this software or derivative works must include the above copyright + * notice. + * + * This software is made available AS IS, and neither the Electronics + * Research Laboratory or the University of California make any + * warranty about the software, its performance or its conformity to + * any specification. + * + * Suggestions, comments, or improvements are welcome and should be + * addressed to: + * + * octtools@eros.berkeley.edu + * ..!ucbvax!eros!octtools + */ + +#if !defined(lint) && !defined(SABER) +static char octtools_copyright[] = "Copyright (c) 1988, 1989, Regents of the University of California. All rights reserved."; +#endif +#endif diff --git a/benchmarks/benchmarks/espresso/cubestr.c b/benchmarks/benchmarks/espresso/cubestr.c new file mode 100644 index 0000000..93ca911 --- /dev/null +++ b/benchmarks/benchmarks/espresso/cubestr.c @@ -0,0 +1,143 @@ +/* + Module: cubestr.c -- routines for managing the global cube structure +*/ + +#include "espresso.h" + +/* + cube_setup -- assume that the fields "num_vars", "num_binary_vars", and + part_size[num_binary_vars .. num_vars-1] are setup, and initialize the + rest of cube and cdata. + + If a part_size is < 0, then the field size is abs(part_size) and the + field read from the input is symbolic. +*/ +void cube_setup() +{ + register int i, var; + register pcube p; + + if (cube.num_binary_vars < 0 || cube.num_vars < cube.num_binary_vars) + fatal("cube size is silly, error in .i/.o or .mv"); + + cube.num_mv_vars = cube.num_vars - cube.num_binary_vars; + cube.output = cube.num_mv_vars > 0 ? cube.num_vars - 1 : -1; + + cube.size = 0; + cube.first_part = ALLOC(int, cube.num_vars); + cube.last_part = ALLOC(int, cube.num_vars); + cube.first_word = ALLOC(int, cube.num_vars); + cube.last_word = ALLOC(int, cube.num_vars); + for(var = 0; var < cube.num_vars; var++) { + if (var < cube.num_binary_vars) + cube.part_size[var] = 2; + cube.first_part[var] = cube.size; + cube.first_word[var] = WHICH_WORD(cube.size); + cube.size += ABS(cube.part_size[var]); + cube.last_part[var] = cube.size - 1; + cube.last_word[var] = WHICH_WORD(cube.size - 1); + } + + cube.var_mask = ALLOC(pset, cube.num_vars); + cube.sparse = ALLOC(int, cube.num_vars); + cube.binary_mask = new_cube(); + cube.mv_mask = new_cube(); + for(var = 0; var < cube.num_vars; var++) { + p = cube.var_mask[var] = new_cube(); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) + set_insert(p, i); + if (var < cube.num_binary_vars) { + INLINEset_or(cube.binary_mask, cube.binary_mask, p); + cube.sparse[var] = 0; + } else { + INLINEset_or(cube.mv_mask, cube.mv_mask, p); + cube.sparse[var] = 1; + } + } + if (cube.num_binary_vars == 0) + cube.inword = -1; + else { + cube.inword = cube.last_word[cube.num_binary_vars - 1]; + cube.inmask = cube.binary_mask[cube.inword] & DISJOINT; + } + + cube.temp = ALLOC(pset, CUBE_TEMP); + for(i = 0; i < CUBE_TEMP; i++) + cube.temp[i] = new_cube(); + cube.fullset = set_fill(new_cube(), cube.size); + cube.emptyset = new_cube(); + + cdata.part_zeros = ALLOC(int, cube.size); + cdata.var_zeros = ALLOC(int, cube.num_vars); + cdata.parts_active = ALLOC(int, cube.num_vars); + cdata.is_unate = ALLOC(int, cube.num_vars); +} + +/* + setdown_cube -- free memory allocated for the cube/cdata structs + (free's all but the part_size array) + + (I wanted to call this cube_setdown, but that violates the 8-character + external routine limit on the IBM !) +*/ +void setdown_cube() +{ + register int i, var; + + FREE(cube.first_part); + FREE(cube.last_part); + FREE(cube.first_word); + FREE(cube.last_word); + FREE(cube.sparse); + + free_cube(cube.binary_mask); + free_cube(cube.mv_mask); + free_cube(cube.fullset); + free_cube(cube.emptyset); + for(var = 0; var < cube.num_vars; var++) + free_cube(cube.var_mask[var]); + FREE(cube.var_mask); + + for(i = 0; i < CUBE_TEMP; i++) + free_cube(cube.temp[i]); + FREE(cube.temp); + + FREE(cdata.part_zeros); + FREE(cdata.var_zeros); + FREE(cdata.parts_active); + FREE(cdata.is_unate); + + cube.first_part = cube.last_part = (int *) NULL; + cube.first_word = cube.last_word = (int *) NULL; + cube.sparse = (int *) NULL; + cube.binary_mask = cube.mv_mask = (pcube) NULL; + cube.fullset = cube.emptyset = (pcube) NULL; + cube.var_mask = cube.temp = (pcube *) NULL; + + cdata.part_zeros = cdata.var_zeros = cdata.parts_active = (int *) NULL; + cdata.is_unate = (bool *) NULL; +} + + +void save_cube_struct() +{ + temp_cube_save = cube; /* structure copy ! */ + temp_cdata_save = cdata; /* "" */ + + cube.first_part = cube.last_part = (int *) NULL; + cube.first_word = cube.last_word = (int *) NULL; + cube.part_size = (int *) NULL; + cube.binary_mask = cube.mv_mask = (pcube) NULL; + cube.fullset = cube.emptyset = (pcube) NULL; + cube.var_mask = cube.temp = (pcube *) NULL; + + cdata.part_zeros = cdata.var_zeros = cdata.parts_active = (int *) NULL; + cdata.is_unate = (bool *) NULL; +} + + +void restore_cube_struct() +{ + cube = temp_cube_save; /* structure copy ! */ + cdata = temp_cdata_save; /* "" */ +} diff --git a/benchmarks/benchmarks/espresso/cvrin.c b/benchmarks/benchmarks/espresso/cvrin.c new file mode 100644 index 0000000..d3388fb --- /dev/null +++ b/benchmarks/benchmarks/espresso/cvrin.c @@ -0,0 +1,793 @@ +/* + module: cvrin.c + purpose: cube and cover input routines +*/ + +#include "espresso.h" + +static bool line_length_error; +static int lineno; + +void skip_line(fpin, fpout, echo) +register FILE *fpin, *fpout; +register bool echo; +{ + register int ch; + while ((ch=getc(fpin)) != EOF && ch != '\n') + if (echo) + putc(ch, fpout); + if (echo) + putc('\n', fpout); + lineno++; +} + +char *get_word(fp, word) +register FILE *fp; +register char *word; +{ + register int ch, i = 0; + while ((ch = getc(fp)) != EOF && isspace(ch)) + ; + word[i++] = ch; + while ((ch = getc(fp)) != EOF && ! isspace(ch)) + word[i++] = ch; + word[i++] = '\0'; + return word; +} + +/* + * Yes, I know this routine is a mess + */ +void read_cube(fp, PLA) +register FILE *fp; +pPLA PLA; +{ + register int var, i; + pcube cf = cube.temp[0], cr = cube.temp[1], cd = cube.temp[2]; + bool savef = FALSE, saved = FALSE, saver = FALSE; + char token[256]; /* for kiss read hack */ + int varx, first, last, offset; /* for kiss read hack */ + + set_clear(cf, cube.size); + + /* Loop and read binary variables */ + for(var = 0; var < cube.num_binary_vars; var++) + switch(getc(fp)) { + case EOF: + goto bad_char; + case '\n': + if (! line_length_error) + fprintf(stderr, "product term(s) %s\n", + "span more than one line (warning only)"); + line_length_error = TRUE; + lineno++; + var--; + break; + case ' ': case '|': case '\t': + var--; + break; + case '2': case '-': + set_insert(cf, var*2+1); + case '0': + set_insert(cf, var*2); + break; + case '1': + set_insert(cf, var*2+1); + break; + case '?': + break; + default: + goto bad_char; + } + + + /* Loop for the all but one of the multiple-valued variables */ + for(var = cube.num_binary_vars; var < cube.num_vars-1; var++) + + /* Read a symbolic multiple-valued variable */ + if (cube.part_size[var] < 0) { + (void) fscanf(fp, "%s", token); + if (equal(token, "-") || equal(token, "ANY")) { + if (kiss && var == cube.num_vars - 2) { + /* leave it empty */ + } else { + /* make it full */ + set_or(cf, cf, cube.var_mask[var]); + } + } else if (equal(token, "~")) { + ; + /* leave it empty ... (?) */ + } else { + if (kiss && var == cube.num_vars - 2) + varx = var - 1, offset = ABS(cube.part_size[var-1]); + else + varx = var, offset = 0; + /* Find the symbolic label in the label table */ + first = cube.first_part[varx]; + last = cube.last_part[varx]; + for(i = first; i <= last; i++) + if (PLA->label[i] == (char *) NULL) { + PLA->label[i] = util_strsav(token); /* add new label */ + set_insert(cf, i+offset); + break; + } else if (equal(PLA->label[i], token)) { + set_insert(cf, i+offset); /* use column i */ + break; + } + if (i > last) { + fprintf(stderr, +"declared size of variable %d (counting from variable 0) is too small\n", var); + exit(-1); + } + } + + } else for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) + switch (getc(fp)) { + case EOF: + goto bad_char; + case '\n': + if (! line_length_error) + fprintf(stderr, "product term(s) %s\n", + "span more than one line (warning only)"); + line_length_error = TRUE; + lineno++; + i--; + break; + case ' ': case '|': case '\t': + i--; + break; + case '1': + set_insert(cf, i); + case '0': + break; + default: + goto bad_char; + } + + /* Loop for last multiple-valued variable */ + if (kiss) { + saver = savef = TRUE; + (void) set_xor(cr, cf, cube.var_mask[cube.num_vars - 2]); + } else + set_copy(cr, cf); + set_copy(cd, cf); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) + switch (getc(fp)) { + case EOF: + goto bad_char; + case '\n': + if (! line_length_error) + fprintf(stderr, "product term(s) %s\n", + "span more than one line (warning only)"); + line_length_error = TRUE; + lineno++; + i--; + break; + case ' ': case '|': case '\t': + i--; + break; + case '4': case '1': + if (PLA->pla_type & F_type) + set_insert(cf, i), savef = TRUE; + break; + case '3': case '0': + if (PLA->pla_type & R_type) + set_insert(cr, i), saver = TRUE; + break; + case '2': case '-': + if (PLA->pla_type & D_type) + set_insert(cd, i), saved = TRUE; + case '~': + break; + default: + goto bad_char; + } + if (savef) PLA->F = sf_addset(PLA->F, cf); + if (saved) PLA->D = sf_addset(PLA->D, cd); + if (saver) PLA->R = sf_addset(PLA->R, cr); + return; + +bad_char: + fprintf(stderr, "(warning): input line #%d ignored\n", lineno); + skip_line(fp, stdout, TRUE); + return; +} +void parse_pla(fp, PLA) +IN FILE *fp; +INOUT pPLA PLA; +{ + int i, var, ch, np, last; + char word[256]; + + lineno = 1; + line_length_error = FALSE; + +loop: + switch(ch = getc(fp)) { + case EOF: + return; + + case '\n': + lineno++; + + case ' ': case '\t': case '\f': case '\r': + break; + + case '#': + (void) ungetc(ch, fp); + skip_line(fp, stdout, echo_comments); + break; + + case '.': + /* .i gives the cube input size (binary-functions only) */ + if (equal(get_word(fp, word), "i")) { + if (cube.fullset != NULL) { + fprintf(stderr, "extra .i ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + if (fscanf(fp, "%d", &cube.num_binary_vars) != 1) + fatal("error reading .i"); + cube.num_vars = cube.num_binary_vars + 1; + cube.part_size = ALLOC(int, cube.num_vars); + } + + /* .o gives the cube output size (binary-functions only) */ + } else if (equal(word, "o")) { + if (cube.fullset != NULL) { + fprintf(stderr, "extra .o ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + if (cube.part_size == NULL) + fatal(".o cannot appear before .i"); + if (fscanf(fp, "%d", &(cube.part_size[cube.num_vars-1]))!=1) + fatal("error reading .o"); + cube_setup(); + PLA_labels(PLA); + } + + /* .mv gives the cube size for a multiple-valued function */ + } else if (equal(word, "mv")) { + if (cube.fullset != NULL) { + fprintf(stderr, "extra .mv ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + if (cube.part_size != NULL) + fatal("cannot mix .i and .mv"); + if (fscanf(fp,"%d %d", + &cube.num_vars,&cube.num_binary_vars) != 2) + fatal("error reading .mv"); + if (cube.num_binary_vars < 0) +fatal("num_binary_vars (second field of .mv) cannot be negative"); + if (cube.num_vars < cube.num_binary_vars) + fatal( +"num_vars (1st field of .mv) must exceed num_binary_vars (2nd field of .mv)"); + cube.part_size = ALLOC(int, cube.num_vars); + for(var=cube.num_binary_vars; var < cube.num_vars; var++) + if (fscanf(fp, "%d", &(cube.part_size[var])) != 1) + fatal("error reading .mv"); + cube_setup(); + PLA_labels(PLA); + } + + /* .p gives the number of product terms -- we ignore it */ + } else if (equal(word, "p")) + (void) fscanf(fp, "%d", &np); + /* .e and .end specify the end of the file */ + else if (equal(word, "e") || equal(word,"end")) + return; + /* .kiss turns on the kiss-hack option */ + else if (equal(word, "kiss")) + kiss = TRUE; + + /* .type specifies a logical type for the PLA */ + else if (equal(word, "type")) { + (void) get_word(fp, word); + for(i = 0; pla_types[i].key != 0; i++) + if (equal(pla_types[i].key + 1, word)) { + PLA->pla_type = pla_types[i].value; + break; + } + if (pla_types[i].key == 0) + fatal("unknown type in .type command"); + + /* parse the labels */ + } else if (equal(word, "ilb")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .ilb or .ob"); + if (PLA->label == NULL) + PLA_labels(PLA); + for(var = 0; var < cube.num_binary_vars; var++) { + (void) get_word(fp, word); + i = cube.first_part[var]; + PLA->label[i+1] = util_strsav(word); + PLA->label[i] = ALLOC(char, strlen(word) + 6); + (void) sprintf(PLA->label[i], "%s.bar", word); + } + } else if (equal(word, "ob")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .ilb or .ob"); + if (PLA->label == NULL) + PLA_labels(PLA); + var = cube.num_vars - 1; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + (void) get_word(fp, word); + PLA->label[i] = util_strsav(word); + } + /* .label assigns labels to multiple-valued variables */ + } else if (equal(word, "label")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .label"); + if (PLA->label == NULL) + PLA_labels(PLA); + if (fscanf(fp, "var=%d", &var) != 1) + fatal("Error reading labels"); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + (void) get_word(fp, word); + PLA->label[i] = util_strsav(word); + } + + } else if (equal(word, "symbolic")) { + symbolic_t *newlist, *p1; + if (read_symbolic(fp, PLA, word, &newlist)) { + if (PLA->symbolic == NIL(symbolic_t)) { + PLA->symbolic = newlist; + } else { + for(p1=PLA->symbolic;p1->next!=NIL(symbolic_t); + p1=p1->next){ + } + p1->next = newlist; + } + } else { + fatal("error reading .symbolic"); + } + + } else if (equal(word, "symbolic-output")) { + symbolic_t *newlist, *p1; + if (read_symbolic(fp, PLA, word, &newlist)) { + if (PLA->symbolic_output == NIL(symbolic_t)) { + PLA->symbolic_output = newlist; + } else { + for(p1=PLA->symbolic_output;p1->next!=NIL(symbolic_t); + p1=p1->next){ + } + p1->next = newlist; + } + } else { + fatal("error reading .symbolic-output"); + } + + /* .phase allows a choice of output phases */ + } else if (equal(word, "phase")) { + if (cube.fullset == NULL) + fatal("PLA size must be declared before .phase"); + if (PLA->phase != NULL) { + fprintf(stderr, "extra .phase ignored\n"); + skip_line(fp, stdout, /* echo */ FALSE); + } else { + do ch = getc(fp); while (ch == ' ' || ch == '\t'); + (void) ungetc(ch, fp); + PLA->phase = set_save(cube.fullset); + last = cube.last_part[cube.num_vars - 1]; + for(i=cube.first_part[cube.num_vars - 1]; i <= last; i++) + if ((ch = getc(fp)) == '0') + set_remove(PLA->phase, i); + else if (ch != '1') + fatal("only 0 or 1 allowed in phase description"); + } + + /* .pair allows for bit-pairing input variables */ + } else if (equal(word, "pair")) { + int j; + if (PLA->pair != NULL) { + fprintf(stderr, "extra .pair ignored\n"); + } else { + ppair pair; + PLA->pair = pair = ALLOC(pair_t, 1); + if (fscanf(fp, "%d", &(pair->cnt)) != 1) + fatal("syntax error in .pair"); + pair->var1 = ALLOC(int, pair->cnt); + pair->var2 = ALLOC(int, pair->cnt); + for(i = 0; i < pair->cnt; i++) { + (void) get_word(fp, word); + if (word[0] == '(') (void) strcpy(word, word+1); + if (label_index(PLA, word, &var, &j)) { + pair->var1[i] = var+1; + } else { + fatal("syntax error in .pair"); + } + + (void) get_word(fp, word); + if (word[strlen(word)-1] == ')') { + word[strlen(word)-1]='\0'; + } + if (label_index(PLA, word, &var, &j)) { + pair->var2[i] = var+1; + } else { + fatal("syntax error in .pair"); + } + } + } + + } else { + if (echo_unknown_commands) + printf("%c%s ", ch, word); + skip_line(fp, stdout, echo_unknown_commands); + } + break; + default: + (void) ungetc(ch, fp); + if (cube.fullset == NULL) { +/* fatal("unknown PLA size, need .i/.o or .mv");*/ + if (echo_comments) + putchar('#'); + skip_line(fp, stdout, echo_comments); + break; + } + if (PLA->F == NULL) { + PLA->F = new_cover(10); + PLA->D = new_cover(10); + PLA->R = new_cover(10); + } + read_cube(fp, PLA); + } + goto loop; +} +/* + read_pla -- read a PLA from a file + + Input stops when ".e" is encountered in the input file, or upon reaching + end of file. + + Returns the PLA in the variable PLA after massaging the "symbolic" + representation into a positional cube notation of the ON-set, OFF-set, + and the DC-set. + + needs_dcset and needs_offset control the computation of the OFF-set + and DC-set (i.e., if either needs to be computed, then it will be + computed via complement only if the corresponding option is TRUE.) + pla_type specifies the interpretation to be used when reading the + PLA. + + The phase of the output functions is adjusted according to the + global option "pos" or according to an imbedded .phase option in + the input file. Note that either phase option implies that the + OFF-set be computed regardless of whether the caller needs it + explicitly or not. + + Bit pairing of the binary variables is performed according to an + imbedded .pair option in the input file. + + The global cube structure also reflects the sizes of the PLA which + was just read. If these fields have already been set, then any + subsequent PLA must conform to these sizes. + + The global flags trace and summary control the output produced + during the read. + + Returns a status code as a result: + EOF (-1) : End of file reached before any data was read + > 0 : Operation successful +*/ + +int read_pla(fp, needs_dcset, needs_offset, pla_type, PLA_return) +IN FILE *fp; +IN bool needs_dcset, needs_offset; +IN int pla_type; +OUT pPLA *PLA_return; +{ + pPLA PLA; + int i, second, third; + long time; + cost_t cost; + + /* Allocate and initialize the PLA structure */ + PLA = *PLA_return = new_PLA(); + PLA->pla_type = pla_type; + + /* Read the pla */ + time = ptime(); + parse_pla(fp, PLA); + + /* Check for nothing on the file -- implies reached EOF */ + if (PLA->F == NULL) { + return EOF; + } + + /* This hack merges the next-state field with the outputs */ + for(i = 0; i < cube.num_vars; i++) { + cube.part_size[i] = ABS(cube.part_size[i]); + } + if (kiss) { + third = cube.num_vars - 3; + second = cube.num_vars - 2; + if (cube.part_size[third] != cube.part_size[second]) { + fprintf(stderr," with .kiss option, third to last and second\n"); + fprintf(stderr, "to last variables must be the same size.\n"); + return EOF; + } + for(i = 0; i < cube.part_size[second]; i++) { + PLA->label[i + cube.first_part[second]] = + util_strsav(PLA->label[i + cube.first_part[third]]); + } + cube.part_size[second] += cube.part_size[cube.num_vars-1]; + cube.num_vars--; + setdown_cube(); + cube_setup(); + } + + if (trace) { + totals(time, READ_TIME, PLA->F, &cost); + } + + /* Decide how to break PLA into ON-set, OFF-set and DC-set */ + time = ptime(); + if (pos || PLA->phase != NULL || PLA->symbolic_output != NIL(symbolic_t)) { + needs_offset = TRUE; + } + if (needs_offset && (PLA->pla_type==F_type || PLA->pla_type==FD_type)) { + free_cover(PLA->R); + PLA->R = complement(cube2list(PLA->F, PLA->D)); + } else if (needs_dcset && PLA->pla_type == FR_type) { + pcover X; + free_cover(PLA->D); + /* hack, why not? */ + X = d1merge(sf_join(PLA->F, PLA->R), cube.num_vars - 1); + PLA->D = complement(cube1list(X)); + free_cover(X); + } else if (PLA->pla_type == R_type || PLA->pla_type == DR_type) { + free_cover(PLA->F); + PLA->F = complement(cube2list(PLA->D, PLA->R)); + } + + if (trace) { + totals(time, COMPL_TIME, PLA->R, &cost); + } + + /* Check for phase rearrangement of the functions */ + if (pos) { + pcover onset = PLA->F; + PLA->F = PLA->R; + PLA->R = onset; + PLA->phase = new_cube(); + set_diff(PLA->phase, cube.fullset, cube.var_mask[cube.num_vars-1]); + } else if (PLA->phase != NULL) { + (void) set_phase(PLA); + } + + /* Setup minimization for two-bit decoders */ + if (PLA->pair != (ppair) NULL) { + set_pair(PLA); + } + + if (PLA->symbolic != NIL(symbolic_t)) { + EXEC(map_symbolic(PLA), "MAP-INPUT ", PLA->F); + } + if (PLA->symbolic_output != NIL(symbolic_t)) { + EXEC(map_output_symbolic(PLA), "MAP-OUTPUT ", PLA->F); + if (needs_offset) { + free_cover(PLA->R); +EXECUTE(PLA->R=complement(cube2list(PLA->F,PLA->D)), COMPL_TIME, PLA->R, cost); + } + } + + return 1; +} + +void PLA_summary(PLA) +pPLA PLA; +{ + int var, i; + symbolic_list_t *p2; + symbolic_t *p1; + + printf("# PLA is %s", PLA->filename); + if (cube.num_binary_vars == cube.num_vars - 1) + printf(" with %d inputs and %d outputs\n", + cube.num_binary_vars, cube.part_size[cube.num_vars - 1]); + else { + printf(" with %d variables (%d binary, mv sizes", + cube.num_vars, cube.num_binary_vars); + for(var = cube.num_binary_vars; var < cube.num_vars; var++) + printf(" %d", cube.part_size[var]); + printf(")\n"); + } + printf("# ON-set cost is %s\n", print_cost(PLA->F)); + printf("# OFF-set cost is %s\n", print_cost(PLA->R)); + printf("# DC-set cost is %s\n", print_cost(PLA->D)); + if (PLA->phase != NULL) + printf("# phase is %s\n", pc1(PLA->phase)); + if (PLA->pair != NULL) { + printf("# two-bit decoders:"); + for(i = 0; i < PLA->pair->cnt; i++) + printf(" (%d %d)", PLA->pair->var1[i], PLA->pair->var2[i]); + printf("\n"); + } + if (PLA->symbolic != NIL(symbolic_t)) { + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + printf("# symbolic: "); + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + printf(" %d", p2->variable); + } + printf("\n"); + } + } + if (PLA->symbolic_output != NIL(symbolic_t)) { + for(p1 = PLA->symbolic_output; p1 != NIL(symbolic_t); p1 = p1->next) { + printf("# output symbolic: "); + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + printf(" %d", p2->pos); + } + printf("\n"); + } + } + (void) fflush(stdout); +} + + +pPLA new_PLA() +{ + pPLA PLA; + + PLA = ALLOC(PLA_t, 1); + PLA->F = PLA->D = PLA->R = (pcover) NULL; + PLA->phase = (pcube) NULL; + PLA->pair = (ppair) NULL; + PLA->label = (char **) NULL; + PLA->filename = (char *) NULL; + PLA->pla_type = 0; + PLA->symbolic = NIL(symbolic_t); + PLA->symbolic_output = NIL(symbolic_t); + return PLA; +} + + +PLA_labels(PLA) +pPLA PLA; +{ + int i; + + PLA->label = ALLOC(char *, cube.size); + for(i = 0; i < cube.size; i++) + PLA->label[i] = (char *) NULL; +} + + +void free_PLA(PLA) +pPLA PLA; +{ + symbolic_list_t *p2, *p2next; + symbolic_t *p1, *p1next; + int i; + + if (PLA->F != (pcover) NULL) + free_cover(PLA->F); + if (PLA->R != (pcover) NULL) + free_cover(PLA->R); + if (PLA->D != (pcover) NULL) + free_cover(PLA->D); + if (PLA->phase != (pcube) NULL) + free_cube(PLA->phase); + if (PLA->pair != (ppair) NULL) { + FREE(PLA->pair->var1); + FREE(PLA->pair->var2); + FREE(PLA->pair); + } + if (PLA->label != NULL) { + for(i = 0; i < cube.size; i++) + if (PLA->label[i] != NULL) + FREE(PLA->label[i]); + FREE(PLA->label); + } + if (PLA->filename != NULL) { + FREE(PLA->filename); + } + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1next) { + for(p2 = p1->symbolic_list; p2 != NIL(symbolic_list_t); p2 = p2next) { + p2next = p2->next; + FREE(p2); + } + p1next = p1->next; + FREE(p1); + } + PLA->symbolic = NIL(symbolic_t); + for(p1 = PLA->symbolic_output; p1 != NIL(symbolic_t); p1 = p1next) { + for(p2 = p1->symbolic_list; p2 != NIL(symbolic_list_t); p2 = p2next) { + p2next = p2->next; + FREE(p2); + } + p1next = p1->next; + FREE(p1); + } + PLA->symbolic_output = NIL(symbolic_t); + FREE(PLA); +} + + +int read_symbolic(fp, PLA, word, retval) +FILE *fp; +pPLA PLA; +char *word; /* scratch string for words */ +symbolic_t **retval; +{ + symbolic_list_t *listp, *prev_listp; + symbolic_label_t *labelp, *prev_labelp; + symbolic_t *newlist; + int i, var; + + newlist = ALLOC(symbolic_t, 1); + newlist->next = NIL(symbolic_t); + newlist->symbolic_list = NIL(symbolic_list_t); + newlist->symbolic_list_length = 0; + newlist->symbolic_label = NIL(symbolic_label_t); + newlist->symbolic_label_length = 0; + prev_listp = NIL(symbolic_list_t); + prev_labelp = NIL(symbolic_label_t); + + for(;;) { + (void) get_word(fp, word); + if (equal(word, ";")) + break; + if (label_index(PLA, word, &var, &i)) { + listp = ALLOC(symbolic_list_t, 1); + listp->variable = var; + listp->pos = i; + listp->next = NIL(symbolic_list_t); + if (prev_listp == NIL(symbolic_list_t)) { + newlist->symbolic_list = listp; + } else { + prev_listp->next = listp; + } + prev_listp = listp; + newlist->symbolic_list_length++; + } else { + return FALSE; + } + } + + for(;;) { + (void) get_word(fp, word); + if (equal(word, ";")) + break; + labelp = ALLOC(symbolic_label_t, 1); + labelp->label = util_strsav(word); + labelp->next = NIL(symbolic_label_t); + if (prev_labelp == NIL(symbolic_label_t)) { + newlist->symbolic_label = labelp; + } else { + prev_labelp->next = labelp; + } + prev_labelp = labelp; + newlist->symbolic_label_length++; + } + + *retval = newlist; + return TRUE; +} + + +int label_index(PLA, word, varp, ip) +pPLA PLA; +char *word; +int *varp; +int *ip; +{ + int var, i; + + if (PLA->label == NIL(char *) || PLA->label[0] == NIL(char)) { + if (sscanf(word, "%d", varp) == 1) { + *ip = *varp; + return TRUE; + } + } else { + for(var = 0; var < cube.num_vars; var++) { + for(i = 0; i < cube.part_size[var]; i++) { + if (equal(PLA->label[cube.first_part[var]+i], word)) { + *varp = var; + *ip = i; + return TRUE; + } + } + } + } + return FALSE; +} diff --git a/benchmarks/benchmarks/espresso/cvrm.c b/benchmarks/benchmarks/espresso/cvrm.c new file mode 100644 index 0000000..1fb21e2 --- /dev/null +++ b/benchmarks/benchmarks/espresso/cvrm.c @@ -0,0 +1,530 @@ +/* + module: cvrm.c + Purpose: miscellaneous cover manipulation + a) verify two covers are equal, check consistency of a cover + b) unravel a multiple-valued cover into minterms + c) sort covers +*/ + +#include "espresso.h" + + +static void cb_unravel(c, start, end, startbase, B1) +IN register pcube c; +IN int start, end; +IN pcube startbase; +INOUT pcover B1; +{ + pcube base = cube.temp[0], p, last; + int expansion, place, skip, var, size, offset; + register int i, j, k, n; + + /* Determine how many cubes it will blow up into, and create a mask + for those parts that have only a single coordinate + */ + expansion = 1; + (void) set_copy(base, startbase); + for(var = start; var <= end; var++) { + if ((size = set_dist(c, cube.var_mask[var])) < 2) { + (void) set_or(base, base, cube.var_mask[var]); + } else { + expansion *= size; + } + } + (void) set_and(base, c, base); + + /* Add the unravelled sets starting at the last element of B1 */ + offset = B1->count; + B1->count += expansion; + foreach_remaining_set(B1, last, GETSET(B1, offset-1), p) { + INLINEset_copy(p, base); + } + + place = expansion; + for(var = start; var <= end; var++) { + if ((size = set_dist(c, cube.var_mask[var])) > 1) { + skip = place; + place = place / size; + n = 0; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + if (is_in_set(c, i)) { + for(j = n; j < expansion; j += skip) { + for(k = 0; k < place; k++) { + p = GETSET(B1, j+k+offset); + (void) set_insert(p, i); + } + } + n += place; + } + } + } + } +} + + +pcover unravel_range(B, start, end) +IN pcover B; +IN int start, end; +{ + pcover B1; + int var, total_size, expansion, size; + register pcube p, last, startbase = cube.temp[1]; + + /* Create the starting base for those variables not being unravelled */ + (void) set_copy(startbase, cube.emptyset); + for(var = 0; var < start; var++) + (void) set_or(startbase, startbase, cube.var_mask[var]); + for(var = end+1; var < cube.num_vars; var++) + (void) set_or(startbase, startbase, cube.var_mask[var]); + + /* Determine how many cubes it will blow up into */ + total_size = 0; + foreach_set(B, last, p) { + expansion = 1; + for(var = start; var <= end; var++) + if ((size = set_dist(p, cube.var_mask[var])) >= 2) + if ((expansion *= size) > 1000000) + fatal("unreasonable expansion in unravel"); + total_size += expansion; + } + + /* We can now allocate a cover of exactly the correct size */ + B1 = new_cover(total_size); + foreach_set(B, last, p) { + cb_unravel(p, start, end, startbase, B1); + } + free_cover(B); + return B1; +} + + +pcover unravel(B, start) +IN pcover B; +IN int start; +{ + return unravel_range(B, start, cube.num_vars-1); +} + +/* lex_sort -- sort cubes in a standard lexical fashion */ +pcover lex_sort(T) +pcover T; +{ + pcover T1 = sf_unlist(sf_sort(T, lex_order), T->count, T->sf_size); + free_cover(T); + return T1; +} + + +/* size_sort -- sort cubes by their size */ +pcover size_sort(T) +pcover T; +{ + pcover T1 = sf_unlist(sf_sort(T, descend), T->count, T->sf_size); + free_cover(T); + return T1; +} + + +/* mini_sort -- sort cubes according to the heuristics of mini */ +pcover mini_sort(F, compare) +pcover F; +int (*compare)(); +{ + register int *count, cnt, n = cube.size, i; + register pcube p, last; + pcover F_sorted; + pcube *F1; + + /* Perform a column sum over the set family */ + count = sf_count(F); + + /* weight is "inner product of the cube and the column sums" */ + foreach_set(F, last, p) { + cnt = 0; + for(i = 0; i < n; i++) + if (is_in_set(p, i)) + cnt += count[i]; + PUTSIZE(p, cnt); + } + FREE(count); + + /* use qsort to sort the array */ + qsort((char *) (F1 = sf_list(F)), F->count, sizeof(pcube), compare); + F_sorted = sf_unlist(F1, F->count, F->sf_size); + free_cover(F); + + return F_sorted; +} + + +/* sort_reduce -- Espresso strategy for ordering the cubes before reduction */ +pcover sort_reduce(T) +IN pcover T; +{ + register pcube p, last, largest = NULL; + register int bestsize = -1, size, n = cube.num_vars; + pcover T_sorted; + pcube *T1; + + if (T->count == 0) + return T; + + /* find largest cube */ + foreach_set(T, last, p) + if ((size = set_ord(p)) > bestsize) + largest = p, bestsize = size; + + foreach_set(T, last, p) + PUTSIZE(p, ((n - cdist(largest,p)) << 7) + MIN(set_ord(p),127)); + + qsort((char *) (T1 = sf_list(T)), T->count, sizeof(pcube), descend); + T_sorted = sf_unlist(T1, T->count, T->sf_size); + free_cover(T); + + return T_sorted; +} + +pcover random_order(F) +register pcover F; +{ + pset temp; + register int i, k; +#ifdef RANDOM + long random(); +#endif + + temp = set_new(F->sf_size); + for(i = F->count - 1; i > 0; i--) { + /* Choose a random number between 0 and i */ +#ifdef RANDOM + k = random() % i; +#else + /* this is not meant to be really used; just provides an easy + "out" if random() and srandom() aren't around + */ + k = (i*23 + 997) % i; +#endif + /* swap sets i and k */ + set_copy(temp, GETSET(F, k)); + set_copy(GETSET(F, k), GETSET(F, i)); + set_copy(GETSET(F, i), temp); + } + set_free(temp); + return F; +} + +/* + * cubelist_partition -- take a cubelist T and see if it has any components; + * if so, return cubelist's of the two partitions A and B; the return value + * is the size of the partition; if not, A and B + * are undefined and the return value is 0 + */ +int cubelist_partition(T, A, B, comp_debug) +pcube *T; /* a list of cubes */ +pcube **A, **B; /* cubelist of partition and remainder */ +unsigned int comp_debug; +{ + register pcube *T1, p, seed, cof; + pcube *A1, *B1; + bool change; + int count, numcube; + + numcube = CUBELISTSIZE(T); + + /* Mark all cubes -- covered cubes belong to the partition */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + RESET(p, COVERED); + } + + /* + * Extract a partition from the cubelist T; start with the first cube as a + * seed, and then pull in all cubes which share a variable with the seed; + * iterate until no new cubes are brought into the partition. + */ + seed = set_save(T[2]); + cof = T[0]; + SET(T[2], COVERED); + count = 1; + + do { + change = FALSE; + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (! TESTP(p, COVERED) && ccommon(p, seed, cof)) { + INLINEset_and(seed, seed, p); + SET(p, COVERED); + change = TRUE; + count++; + } + + } + } while (change); + + set_free(seed); + + if (comp_debug) { + printf("COMPONENT_REDUCTION: split into %d %d\n", + count, numcube - count); + } + + if (count != numcube) { + /* Allocate and setup the cubelist's for the two partitions */ + *A = A1 = ALLOC(pcube, numcube+3); + *B = B1 = ALLOC(pcube, numcube+3); + (*A)[0] = set_save(T[0]); + (*B)[0] = set_save(T[0]); + A1 = *A + 2; + B1 = *B + 2; + + /* Loop over the cubes in T and distribute to A and B */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (TESTP(p, COVERED)) { + *A1++ = p; + } else { + *B1++ = p; + } + } + + /* Stuff needed at the end of the cubelist's */ + *A1++ = NULL; + (*A)[1] = (pcube) A1; + *B1++ = NULL; + (*B)[1] = (pcube) B1; + } + + return numcube - count; +} + +/* + * quick cofactor against a single output function + */ +pcover cof_output(T, i) +pcover T; +register int i; +{ + pcover T1; + register pcube p, last, pdest, mask; + + mask = cube.var_mask[cube.output]; + T1 = new_cover(T->count); + foreach_set(T, last, p) { + if (is_in_set(p, i)) { + pdest = GETSET(T1, T1->count++); + INLINEset_or(pdest, p, mask); + RESET(pdest, PRIME); + } + } + return T1; +} + + +/* + * quick intersection against a single output function + */ +pcover uncof_output(T, i) +pcover T; +int i; +{ + register pcube p, last, mask; + + if (T == NULL) { + return T; + } + + mask = cube.var_mask[cube.output]; + foreach_set(T, last, p) { + INLINEset_diff(p, p, mask); + set_insert(p, i); + } + return T; +} + + +/* + * A generic routine to perform an operation for each output function + * + * func() is called with a PLA for each output function (with the output + * part effectively removed). + * func1() is called after reforming the equivalent output function + * + * Each function returns TRUE if process is to continue + */ +foreach_output_function(PLA, func, func1) +pPLA PLA; +int (*func)(); +int (*func1)(); +{ + pPLA PLA1; + int i; + + /* Loop for each output function */ + for(i = 0; i < cube.part_size[cube.output]; i++) { + + /* cofactor on the output part */ + PLA1 = new_PLA(); + PLA1->F = cof_output(PLA->F, i + cube.first_part[cube.output]); + PLA1->R = cof_output(PLA->R, i + cube.first_part[cube.output]); + PLA1->D = cof_output(PLA->D, i + cube.first_part[cube.output]); + + /* Call a routine to do something with the cover */ + if ((*func)(PLA1, i) == 0) { + free_PLA(PLA1); + return 0; + } + + /* intersect with the particular output part again */ + PLA1->F = uncof_output(PLA1->F, i + cube.first_part[cube.output]); + PLA1->R = uncof_output(PLA1->R, i + cube.first_part[cube.output]); + PLA1->D = uncof_output(PLA1->D, i + cube.first_part[cube.output]); + + /* Call a routine to do something with the final result */ + if ((*func1)(PLA1, i) == 0) { + free_PLA(PLA1); + return 0; + } + + /* Cleanup for next go-around */ + free_PLA(PLA1); + + } + return 0; +} + +static pcover Fmin; +static pcube phase; + +/* + * minimize each output function individually + */ +void so_espresso(PLA, strategy) +pPLA PLA; +int strategy; +{ + Fmin = new_cover(PLA->F->count); + if (strategy == 0) { + foreach_output_function(PLA, so_do_espresso, so_save); + } else { + foreach_output_function(PLA, so_do_exact, so_save); + } + sf_free(PLA->F); + PLA->F = Fmin; +} + + +/* + * minimize each output function, choose function or complement based on the + * one with the fewer number of terms + */ +void so_both_espresso(PLA, strategy) +pPLA PLA; +int strategy; +{ + phase = set_save(cube.fullset); + Fmin = new_cover(PLA->F->count); + if (strategy == 0) { + foreach_output_function(PLA, so_both_do_espresso, so_both_save); + } else { + foreach_output_function(PLA, so_both_do_exact, so_both_save); + } + sf_free(PLA->F); + PLA->F = Fmin; + PLA->phase = phase; +} + + +int so_do_espresso(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + skip_make_sparse = 1; + (void) sprintf(word, "ESPRESSO-POS(%d)", i); + EXEC_S(PLA->F = espresso(PLA->F, PLA->D, PLA->R), word, PLA->F); + return 1; +} + + +int so_do_exact(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + skip_make_sparse = 1; + (void) sprintf(word, "EXACT-POS(%d)", i); + EXEC_S(PLA->F = minimize_exact(PLA->F, PLA->D, PLA->R, 1), word, PLA->F); + return 1; +} + + +/*ARGSUSED*/ +int so_save(PLA, i) +pPLA PLA; +int i; +{ + Fmin = sf_append(Fmin, PLA->F); /* disposes of PLA->F */ + PLA->F = NULL; + return 1; +} + + +int so_both_do_espresso(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + (void) sprintf(word, "ESPRESSO-POS(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->F = espresso(PLA->F, PLA->D, PLA->R), word, PLA->F); + + /* minimize the single-output function (off-set) */ + (void) sprintf(word, "ESPRESSO-NEG(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->R = espresso(PLA->R, PLA->D, PLA->F), word, PLA->R); + + return 1; +} + + +int so_both_do_exact(PLA, i) +pPLA PLA; +int i; +{ + char word[32]; + + /* minimize the single-output function (on-set) */ + (void) sprintf(word, "EXACT-POS(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->F = minimize_exact(PLA->F, PLA->D, PLA->R, 1), word, PLA->F); + + /* minimize the single-output function (off-set) */ + (void) sprintf(word, "EXACT-NEG(%d)", i); + skip_make_sparse = 1; + EXEC_S(PLA->R = minimize_exact(PLA->R, PLA->D, PLA->F, 1), word, PLA->R); + + return 1; +} + + +int so_both_save(PLA, i) +pPLA PLA; +int i; +{ + if (PLA->F->count > PLA->R->count) { + sf_free(PLA->F); + PLA->F = PLA->R; + PLA->R = NULL; + i += cube.first_part[cube.output]; + set_remove(phase, i); + } else { + sf_free(PLA->R); + PLA->R = NULL; + } + Fmin = sf_append(Fmin, PLA->F); + PLA->F = NULL; + return 1; +} diff --git a/benchmarks/benchmarks/espresso/cvrmisc.c b/benchmarks/benchmarks/espresso/cvrmisc.c new file mode 100644 index 0000000..f0be0c3 --- /dev/null +++ b/benchmarks/benchmarks/espresso/cvrmisc.c @@ -0,0 +1,140 @@ +#include "espresso.h" + + +/* cost -- compute the cost of a cover */ +void cover_cost(F, cost) +IN pcover F; +INOUT pcost cost; +{ + register pcube p, last; + pcube *T; + int var; + + /* use the routine used by cofactor to decide splitting variables */ + massive_count(T = cube1list(F)); + free_cubelist(T); + + cost->cubes = F->count; + cost->total = cost->in = cost->out = cost->mv = cost->primes = 0; + + /* Count transistors (zeros) for each binary variable (inputs) */ + for(var = 0; var < cube.num_binary_vars; var++) + cost->in += cdata.var_zeros[var]; + + /* Count transistors for each mv variable based on sparse/dense */ + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) + if (cube.sparse[var]) + cost->mv += F->count * cube.part_size[var] - cdata.var_zeros[var]; + else + cost->mv += cdata.var_zeros[var]; + + /* Count the transistors (ones) for the output variable */ + if (cube.num_binary_vars != cube.num_vars) { + var = cube.num_vars - 1; + cost->out = F->count * cube.part_size[var] - cdata.var_zeros[var]; + } + + /* Count the number of nonprime cubes */ + /* + THIS IS A BUG! p is never set! EDB... + + foreach_set(F, last, p) + cost->primes += TESTP(p, PRIME) != 0; + */ + + /* Count the total number of literals */ + cost->total = cost->in + cost->out + cost->mv; +} + + +/* fmt_cost -- return a string which reports the "cost" of a cover */ +char *fmt_cost(cost) +IN pcost cost; +{ + static char s[200]; + + if (cube.num_binary_vars == cube.num_vars - 1) { + int v1 = cost->primes + 1; + sprintf (s, "%d", v1); + (void) sprintf(s, "c=%d(%d) in=%d out=%d tot=%d", + cost->cubes, cost->cubes - cost->primes, cost->in, + cost->out, cost->total); + } else { + (void) sprintf(s, "c=%d(%d) in=%d mv=%d out=%d", + cost->cubes, cost->cubes - cost->primes, cost->in, + cost->mv, cost->out); + } + return s; +} + + +char *print_cost(F) +IN pcover F; +{ + cost_t cost; + cover_cost(F, &cost); + return fmt_cost(&cost); +} + + +/* copy_cost -- copy a cost function from s to d */ +void copy_cost(s, d) +pcost s, d; +{ + d->cubes = s->cubes; + d->in = s->in; + d->out = s->out; + d->mv = s->mv; + d->total = s->total; + d->primes = s->primes; +} + + +/* size_stamp -- print single line giving the size of a cover */ +void size_stamp(T, name) +IN pcover T; +IN char *name; +{ + printf("# %s\tCost is %s\n", name, print_cost(T)); + (void) fflush(stdout); +} + + +/* print_trace -- print a line reporting size and time after a function */ +void print_trace(T, name, time) +pcover T; +char *name; +long time; +{ + printf("# %s\tTime was %s, cost is %s\n", + name, print_time(time), print_cost(T)); + (void) fflush(stdout); +} + + +/* totals -- add time spent in the function into the totals */ +void totals(time, i, T, cost) +long time; +int i; +pcover T; +pcost cost; +{ + time = ptime() - time; + total_time[i] += time; + total_calls[i]++; + cover_cost(T, cost); + if (trace) { + printf("# %s\tTime was %s, cost is %s\n", + total_name[i], print_time(time), fmt_cost(cost)); + (void) fflush(stdout); + } +} + + +/* fatal -- report fatal error message and take a dive */ +void fatal(s) +char *s; +{ + fprintf(stderr, "espresso: %s\n", s); + exit(1); +} diff --git a/benchmarks/benchmarks/espresso/cvrout.c b/benchmarks/benchmarks/espresso/cvrout.c new file mode 100644 index 0000000..a8c7e67 --- /dev/null +++ b/benchmarks/benchmarks/espresso/cvrout.c @@ -0,0 +1,588 @@ +/* + module: cvrout.c + purpose: cube and cover output routines +*/ + +#include "espresso.h" + +void fprint_pla(fp, PLA, output_type) +INOUT FILE *fp; +IN pPLA PLA; +IN int output_type; +{ + int num; + register pcube last, p; + + if ((output_type & CONSTRAINTS_type) != 0) { + output_symbolic_constraints(fp, PLA, 0); + output_type &= ~ CONSTRAINTS_type; + if (output_type == 0) { + return; + } + } + + if ((output_type & SYMBOLIC_CONSTRAINTS_type) != 0) { + output_symbolic_constraints(fp, PLA, 1); + output_type &= ~ SYMBOLIC_CONSTRAINTS_type; + if (output_type == 0) { + return; + } + } + + if (output_type == PLEASURE_type) { + pls_output(PLA); + } else if (output_type == EQNTOTT_type) { + eqn_output(PLA); + } else if (output_type == KISS_type) { + kiss_output(fp, PLA); + } else { + fpr_header(fp, PLA, output_type); + + num = 0; + if (output_type & F_type) num += (PLA->F)->count; + if (output_type & D_type) num += (PLA->D)->count; + if (output_type & R_type) num += (PLA->R)->count; + fprintf(fp, ".p %d\n", num); + + /* quick patch 01/17/85 to support TPLA ! */ + if (output_type == F_type) { + foreach_set(PLA->F, last, p) { + print_cube(fp, p, "01"); + } + fprintf(fp, ".e\n"); + } else { + if (output_type & F_type) { + foreach_set(PLA->F, last, p) { + print_cube(fp, p, "~1"); + } + } + if (output_type & D_type) { + foreach_set(PLA->D, last, p) { + print_cube(fp, p, "~2"); + } + } + if (output_type & R_type) { + foreach_set(PLA->R, last, p) { + print_cube(fp, p, "~0"); + } + } + fprintf(fp, ".end\n"); + } + } +} + +void fpr_header(fp, PLA, output_type) +FILE *fp; +pPLA PLA; +int output_type; +{ + register int i, var; + int first, last; + + /* .type keyword gives logical type */ + if (output_type != F_type) { + fprintf(fp, ".type "); + if (output_type & F_type) putc('f', fp); + if (output_type & D_type) putc('d', fp); + if (output_type & R_type) putc('r', fp); + putc('\n', fp); + } + + /* Check for binary or multiple-valued labels */ + if (cube.num_mv_vars <= 1) { + fprintf(fp, ".i %d\n", cube.num_binary_vars); + if (cube.output != -1) + fprintf(fp, ".o %d\n", cube.part_size[cube.output]); + } else { + fprintf(fp, ".mv %d %d", cube.num_vars, cube.num_binary_vars); + for(var = cube.num_binary_vars; var < cube.num_vars; var++) + fprintf(fp, " %d", cube.part_size[var]); + fprintf(fp, "\n"); + } + + /* binary valued labels */ + if (PLA->label != NIL(char *) && PLA->label[1] != NIL(char) + && cube.num_binary_vars > 0) { + fprintf(fp, ".ilb"); + for(var = 0; var < cube.num_binary_vars; var++) + fprintf(fp, " %s", INLABEL(var)); + putc('\n', fp); + } + + /* output-part (last multiple-valued variable) labels */ + if (PLA->label != NIL(char *) && + PLA->label[cube.first_part[cube.output]] != NIL(char) + && cube.output != -1) { + fprintf(fp, ".ob"); + for(i = 0; i < cube.part_size[cube.output]; i++) + fprintf(fp, " %s", OUTLABEL(i)); + putc('\n', fp); + } + + /* multiple-valued labels */ + for(var = cube.num_binary_vars; var < cube.num_vars-1; var++) { + first = cube.first_part[var]; + last = cube.last_part[var]; + if (PLA->label != NULL && PLA->label[first] != NULL) { + fprintf(fp, ".label var=%d", var); + for(i = first; i <= last; i++) { + fprintf(fp, " %s", PLA->label[i]); + } + putc('\n', fp); + } + } + + if (PLA->phase != (pcube) NULL) { + first = cube.first_part[cube.output]; + last = cube.last_part[cube.output]; + fprintf(fp, "#.phase "); + for(i = first; i <= last; i++) + putc(is_in_set(PLA->phase,i) ? '1' : '0', fp); + fprintf(fp, "\n"); + } +} + +void pls_output(PLA) +IN pPLA PLA; +{ + register pcube last, p; + + printf(".option unmerged\n"); + makeup_labels(PLA); + pls_label(PLA, stdout); + pls_group(PLA, stdout); + printf(".p %d\n", PLA->F->count); + foreach_set(PLA->F, last, p) { + print_expanded_cube(stdout, p, PLA->phase); + } + printf(".end\n"); +} + + +void pls_group(PLA, fp) +pPLA PLA; +FILE *fp; +{ + int var, i, col, len; + + fprintf(fp, "\n.group"); + col = 6; + for(var = 0; var < cube.num_vars-1; var++) { + fprintf(fp, " ("), col += 2; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + len = strlen(PLA->label[i]); + if (col + len > 75) + fprintf(fp, " \\\n"), col = 0; + else if (i != 0) + putc(' ', fp), col += 1; + fprintf(fp, "%s", PLA->label[i]), col += len; + } + fprintf(fp, ")"), col += 1; + } + fprintf(fp, "\n"); +} + + +void pls_label(PLA, fp) +pPLA PLA; +FILE *fp; +{ + int var, i, col, len; + + fprintf(fp, ".label"); + col = 6; + for(var = 0; var < cube.num_vars; var++) + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + len = strlen(PLA->label[i]); + if (col + len > 75) + fprintf(fp, " \\\n"), col = 0; + else + putc(' ', fp), col += 1; + fprintf(fp, "%s", PLA->label[i]), col += len; + } +} + + + +/* + eqntott output mode -- output algebraic equations +*/ +void eqn_output(PLA) +pPLA PLA; +{ + register pcube p, last; + register int i, var, col, len; + int x; + bool firstand, firstor; + + if (cube.output == -1) + fatal("Cannot have no-output function for EQNTOTT output mode"); + if (cube.num_mv_vars != 1) + fatal("Must have binary-valued function for EQNTOTT output mode"); + makeup_labels(PLA); + + /* Write a single equation for each output */ + for(i = 0; i < cube.part_size[cube.output]; i++) { + printf("%s = ", OUTLABEL(i)); + col = strlen(OUTLABEL(i)) + 3; + firstor = TRUE; + + /* Write product terms for each cube in this output */ + foreach_set(PLA->F, last, p) + if (is_in_set(p, i + cube.first_part[cube.output])) { + if (firstor) + printf("("), col += 1; + else + printf(" | ("), col += 4; + firstor = FALSE; + firstand = TRUE; + + /* print out a product term */ + for(var = 0; var < cube.num_binary_vars; var++) + if ((x=GETINPUT(p, var)) != DASH) { + len = strlen(INLABEL(var)); + if (col+len > 72) + printf("\n "), col = 4; + if (! firstand) + printf("&"), col += 1; + firstand = FALSE; + if (x == ZERO) + printf("!"), col += 1; + printf("%s", INLABEL(var)), col += len; + } + printf(")"), col += 1; + } + printf(";\n\n"); + } +} + + +char *fmt_cube(c, out_map, s) +register pcube c; +register char *out_map, *s; +{ + register int i, var, last, len = 0; + + for(var = 0; var < cube.num_binary_vars; var++) { + s[len++] = "?01-" [GETINPUT(c, var)]; + } + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + s[len++] = ' '; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + s[len++] = "01" [is_in_set(c, i) != 0]; + } + } + if (cube.output != -1) { + last = cube.last_part[cube.output]; + s[len++] = ' '; + for(i = cube.first_part[cube.output]; i <= last; i++) { + s[len++] = out_map [is_in_set(c, i) != 0]; + } + } + s[len] = '\0'; + return s; +} + + +void print_cube(fp, c, out_map) +register FILE *fp; +register pcube c; +register char *out_map; +{ + register int i, var, ch; + int last; + + for(var = 0; var < cube.num_binary_vars; var++) { + ch = "?01-" [GETINPUT(c, var)]; + putc(ch, fp); + } + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + putc(' ', fp); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + ch = "01" [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + if (cube.output != -1) { + last = cube.last_part[cube.output]; + putc(' ', fp); + for(i = cube.first_part[cube.output]; i <= last; i++) { + ch = out_map [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + putc('\n', fp); +} + + +void print_expanded_cube(fp, c, phase) +register FILE *fp; +register pcube c; +pcube phase; +{ + register int i, var, ch; + char *out_map; + + for(var = 0; var < cube.num_binary_vars; var++) { + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + ch = "~1" [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + ch = "1~" [is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + if (cube.output != -1) { + var = cube.num_vars - 1; + putc(' ', fp); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + if (phase == (pcube) NULL || is_in_set(phase, i)) { + out_map = "~1"; + } else { + out_map = "~0"; + } + ch = out_map[is_in_set(c, i) != 0]; + putc(ch, fp); + } + } + putc('\n', fp); +} + + +char *pc1(c) pcube c; +{static char s1[256];return fmt_cube(c, "01", s1);} +char *pc2(c) pcube c; +{static char s2[256];return fmt_cube(c, "01", s2);} + + +void debug_print(T, name, level) +pcube *T; +char *name; +int level; +{ + register pcube *T1, p, temp; + register int cnt; + + cnt = CUBELISTSIZE(T); + temp = new_cube(); + if (verbose_debug && level == 0) + printf("\n"); + printf("%s[%d]: ord(T)=%d\n", name, level, cnt); + if (verbose_debug) { + printf("cofactor=%s\n", pc1(T[0])); + for(T1 = T+2, cnt = 1; (p = *T1++) != (pcube) NULL; cnt++) + printf("%4d. %s\n", cnt, pc1(set_or(temp, p, T[0]))); + } + free_cube(temp); +} + + +void debug1_print(T, name, num) +pcover T; +char *name; +int num; +{ + register int cnt = 1; + register pcube p, last; + + if (verbose_debug && num == 0) + printf("\n"); + printf("%s[%d]: ord(T)=%d\n", name, num, T->count); + if (verbose_debug) + foreach_set(T, last, p) + printf("%4d. %s\n", cnt++, pc1(p)); +} + + +void cprint(T) +pcover T; +{ + register pcube p, last; + + foreach_set(T, last, p) + printf("%s\n", pc1(p)); +} + + +int makeup_labels(PLA) +pPLA PLA; +{ + int var, i, ind; + + if (PLA->label == (char **) NULL) + PLA_labels(PLA); + + for(var = 0; var < cube.num_vars; var++) + for(i = 0; i < cube.part_size[var]; i++) { + ind = cube.first_part[var] + i; + if (PLA->label[ind] == (char *) NULL) { + PLA->label[ind] = ALLOC(char, 15); + if (var < cube.num_binary_vars) + if ((i % 2) == 0) + (void) sprintf(PLA->label[ind], "v%d.bar", var); + else + (void) sprintf(PLA->label[ind], "v%d", var); + else + (void) sprintf(PLA->label[ind], "v%d.%d", var, i); + } + } +} + + +kiss_output(fp, PLA) +FILE *fp; +pPLA PLA; +{ + register pset last, p; + + foreach_set(PLA->F, last, p) { + kiss_print_cube(fp, PLA, p, "~1"); + } + foreach_set(PLA->D, last, p) { + kiss_print_cube(fp, PLA, p, "~2"); + } +} + + +kiss_print_cube(fp, PLA, p, out_string) +FILE *fp; +pPLA PLA; +pcube p; +char *out_string; +{ + register int i, var; + int part, x; + + for(var = 0; var < cube.num_binary_vars; var++) { + x = "?01-" [GETINPUT(p, var)]; + putc(x, fp); + } + + for(var = cube.num_binary_vars; var < cube.num_vars - 1; var++) { + putc(' ', fp); + if (setp_implies(cube.var_mask[var], p)) { + putc('-', fp); + } else { + part = -1; + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + if (is_in_set(p, i)) { + if (part != -1) { + fatal("more than 1 part in a symbolic variable\n"); + } + part = i; + } + } + if (part == -1) { + putc('~', fp); /* no parts, hope its an output ... */ + } else { + (void) fputs(PLA->label[part], fp); + } + } + } + + if ((var = cube.output) != -1) { + putc(' ', fp); + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + x = out_string [is_in_set(p, i) != 0]; + putc(x, fp); + } + } + + putc('\n', fp); +} + +output_symbolic_constraints(fp, PLA, output_symbolic) +FILE *fp; +pPLA PLA; +int output_symbolic; +{ + pset_family A; + register int i, j; + int size, var, npermute, *permute, *weight, noweight; + + if ((cube.num_vars - cube.num_binary_vars) <= 1) { + return 0; + } + makeup_labels(PLA); + + for(var=cube.num_binary_vars; var < cube.num_vars-1; var++) { + + /* pull out the columns for variable "var" */ + npermute = cube.part_size[var]; + permute = ALLOC(int, npermute); + for(i=0; i < npermute; i++) { + permute[i] = cube.first_part[var] + i; + } + A = sf_permute(sf_save(PLA->F), permute, npermute); + FREE(permute); + + + /* Delete the singletons and the full sets */ + noweight = 0; + for(i = 0; i < A->count; i++) { + size = set_ord(GETSET(A,i)); + if (size == 1 || size == A->sf_size) { + sf_delset(A, i--); + noweight++; + } + } + + + /* Count how many times each is duplicated */ + weight = ALLOC(int, A->count); + for(i = 0; i < A->count; i++) { + RESET(GETSET(A, i), COVERED); + } + for(i = 0; i < A->count; i++) { + weight[i] = 0; + if (! TESTP(GETSET(A,i), COVERED)) { + weight[i] = 1; + for(j = i+1; j < A->count; j++) { + if (setp_equal(GETSET(A,i), GETSET(A,j))) { + weight[i]++; + SET(GETSET(A,j), COVERED); + } + } + } + } + + + /* Print out the contraints */ + if (! output_symbolic) { + (void) fprintf(fp, + "# Symbolic constraints for variable %d (Numeric form)\n", var); + (void) fprintf(fp, "# unconstrained weight = %d\n", noweight); + (void) fprintf(fp, "num_codes=%d\n", cube.part_size[var]); + for(i = 0; i < A->count; i++) { + if (weight[i] > 0) { + (void) fprintf(fp, "weight=%d: ", weight[i]); + for(j = 0; j < A->sf_size; j++) { + if (is_in_set(GETSET(A,i), j)) { + (void) fprintf(fp, " %d", j); + } + } + (void) fprintf(fp, "\n"); + } + } + } else { + (void) fprintf(fp, + "# Symbolic constraints for variable %d (Symbolic form)\n", var); + for(i = 0; i < A->count; i++) { + if (weight[i] > 0) { + (void) fprintf(fp, "# w=%d: (", weight[i]); + for(j = 0; j < A->sf_size; j++) { + if (is_in_set(GETSET(A,i), j)) { + (void) fprintf(fp, " %s", + PLA->label[cube.first_part[var]+j]); + } + } + (void) fprintf(fp, " )\n"); + } + } + FREE(weight); + } + } +} diff --git a/benchmarks/benchmarks/espresso/dominate.c b/benchmarks/benchmarks/espresso/dominate.c new file mode 100644 index 0000000..882a43c --- /dev/null +++ b/benchmarks/benchmarks/espresso/dominate.c @@ -0,0 +1,90 @@ +#include "espresso.h" +#include "mincov_int.h" + + +int +sm_row_dominance(A) +sm_matrix *A; +{ + register sm_row *prow, *prow1; + register sm_col *pcol, *least_col; + register sm_element *p, *pnext; + int rowcnt; + + rowcnt = A->nrows; + + /* Check each row against all other rows */ + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + + /* Among all columns with a 1 in this row, choose smallest */ + least_col = sm_get_col(A, prow->first_col->col_num); + for(p = prow->first_col->next_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + if (pcol->length < least_col->length) { + least_col = pcol; + } + } + + /* Only check for containment against rows in this column */ + for(p = least_col->first_row; p != 0; p = pnext) { + pnext = p->next_row; + + prow1 = sm_get_row(A, p->row_num); + if ((prow1->length > prow->length) || + (prow1->length == prow->length && + prow1->row_num > prow->row_num)) { + if (sm_row_contains(prow, prow1)) { + sm_delrow(A, prow1->row_num); + } + } + } + } + + return rowcnt - A->nrows; +} + +int +sm_col_dominance(A, weight) +sm_matrix *A; +int *weight; +{ + register sm_row *prow; + register sm_col *pcol, *pcol1; + register sm_element *p; + sm_row *least_row; + sm_col *next_col; + int colcnt; + + colcnt = A->ncols; + + /* Check each column against all other columns */ + for(pcol = A->first_col; pcol != 0; pcol = next_col) { + next_col = pcol->next_col; + + /* Check all rows to find the one with fewest elements */ + least_row = sm_get_row(A, pcol->first_row->row_num); + for(p = pcol->first_row->next_row; p != 0; p = p->next_row) { + prow = sm_get_row(A, p->row_num); + if (prow->length < least_row->length) { + least_row = prow; + } + } + + /* Only check for containment against columns in this row */ + for(p = least_row->first_col; p != 0; p = p->next_col) { + pcol1 = sm_get_col(A, p->col_num); + if (weight != 0 && weight[pcol1->col_num] > weight[pcol->col_num]) + continue; + if ((pcol1->length > pcol->length) || + (pcol1->length == pcol->length && + pcol1->col_num > pcol->col_num)) { + if (sm_col_contains(pcol, pcol1)) { + sm_delcol(A, pcol->col_num); + break; + } + } + } + } + + return colcnt - A->ncols; +} diff --git a/benchmarks/benchmarks/espresso/equiv.c b/benchmarks/benchmarks/espresso/equiv.c new file mode 100644 index 0000000..be10542 --- /dev/null +++ b/benchmarks/benchmarks/espresso/equiv.c @@ -0,0 +1,85 @@ +#include "espresso.h" + + +find_equiv_outputs(PLA) +pPLA PLA; +{ + int i, j, ipart, jpart, some_equiv; + pcover *R, *F; + + some_equiv = FALSE; + + makeup_labels(PLA); + + F = ALLOC(pcover, cube.part_size[cube.output]); + R = ALLOC(pcover, cube.part_size[cube.output]); + + for(i = 0; i < cube.part_size[cube.output]; i++) { + ipart = cube.first_part[cube.output] + i; + R[i] = cof_output(PLA->R, ipart); + F[i] = complement(cube1list(R[i])); + } + + for(i = 0; i < cube.part_size[cube.output]-1; i++) { + for(j = i+1; j < cube.part_size[cube.output]; j++) { + ipart = cube.first_part[cube.output] + i; + jpart = cube.first_part[cube.output] + j; + + if (check_equiv(F[i], F[j])) { + printf("# Outputs %d and %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } else if (check_equiv(F[i], R[j])) { + printf("# Outputs %d and NOT %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } else if (check_equiv(R[i], F[j])) { + printf("# Outputs NOT %d and %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } else if (check_equiv(R[i], R[j])) { + printf("# Outputs NOT %d and NOT %d (%s and %s) are equivalent\n", + i, j, PLA->label[ipart], PLA->label[jpart]); + some_equiv = TRUE; + } + } + } + + if (! some_equiv) { + printf("# No outputs are equivalent\n"); + } + + for(i = 0; i < cube.part_size[cube.output]; i++) { + free_cover(F[i]); + free_cover(R[i]); + } + FREE(F); + FREE(R); +} + + + +int check_equiv(f1, f2) +pcover f1, f2; +{ + register pcube *f1list, *f2list; + register pcube p, last; + + f1list = cube1list(f1); + foreach_set(f2, last, p) { + if (! cube_is_covered(f1list, p)) { + return FALSE; + } + } + free_cubelist(f1list); + + f2list = cube1list(f2); + foreach_set(f1, last, p) { + if (! cube_is_covered(f2list, p)) { + return FALSE; + } + } + free_cubelist(f2list); + + return TRUE; +} diff --git a/benchmarks/benchmarks/espresso/espresso.c b/benchmarks/benchmarks/espresso/espresso.c new file mode 100644 index 0000000..41dc1d3 --- /dev/null +++ b/benchmarks/benchmarks/espresso/espresso.c @@ -0,0 +1,130 @@ +/* + * Module: espresso.c + * Purpose: The main espresso algorithm + * + * Returns a minimized version of the ON-set of a function + * + * The following global variables affect the operation of Espresso: + * + * MISCELLANEOUS: + * trace + * print trace information as the minimization progresses + * + * remove_essential + * remove essential primes + * + * single_expand + * if true, stop after first expand/irredundant + * + * LAST_GASP or SUPER_GASP strategy: + * use_super_gasp + * uses the super_gasp strategy rather than last_gasp + * + * SETUP strategy: + * recompute_onset + * recompute onset using the complement before starting + * + * unwrap_onset + * unwrap the function output part before first expand + * + * MAKE_SPARSE strategy: + * force_irredundant + * iterates make_sparse to force a minimal solution (used + * indirectly by make_sparse) + * + * skip_make_sparse + * skip the make_sparse step (used by opo only) + */ + +#include "espresso.h" + +pcover espresso(F, D1, R) +pcover F, D1, R; +{ + pcover E, D, Fsave; + pset last, p; + cost_t cost, best_cost; + +begin: + Fsave = sf_save(F); /* save original function */ + D = sf_save(D1); /* make a scratch copy of D */ + + /* Setup has always been a problem */ + if (recompute_onset) { + EXEC(E = simplify(cube1list(F)), "SIMPLIFY ", E); + free_cover(F); + F = E; + } + cover_cost(F, &cost); + if (unwrap_onset && (cube.part_size[cube.num_vars - 1] > 1) + && (cost.out != cost.cubes*cube.part_size[cube.num_vars-1]) + && (cost.out < 5000)) + EXEC(F = sf_contain(unravel(F, cube.num_vars - 1)), "SETUP ", F); + + /* Initial expand and irredundant */ + foreach_set(F, last, p) { + RESET(p, PRIME); + } + EXECUTE(F = expand(F, R, FALSE), EXPAND_TIME, F, cost); + EXECUTE(F = irredundant(F, D), IRRED_TIME, F, cost); + + if (! single_expand) { + if (remove_essential) { + EXECUTE(E = essential(&F, &D), ESSEN_TIME, E, cost); + } else { + E = new_cover(0); + } + + cover_cost(F, &cost); + do { + + /* Repeat inner loop until solution becomes "stable" */ + do { + copy_cost(&cost, &best_cost); + EXECUTE(F = reduce(F, D), REDUCE_TIME, F, cost); + EXECUTE(F = expand(F, R, FALSE), EXPAND_TIME, F, cost); + EXECUTE(F = irredundant(F, D), IRRED_TIME, F, cost); + } while (cost.cubes < best_cost.cubes); + + /* Perturb solution to see if we can continue to iterate */ + copy_cost(&cost, &best_cost); + if (use_super_gasp) { + F = super_gasp(F, D, R, &cost); + if (cost.cubes >= best_cost.cubes) + break; + } else { + F = last_gasp(F, D, R, &cost); + } + + } while (cost.cubes < best_cost.cubes || + (cost.cubes == best_cost.cubes && cost.total < best_cost.total)); + + /* Append the essential cubes to F */ + F = sf_append(F, E); /* disposes of E */ + if (trace) size_stamp(F, "ADJUST "); + } + + /* Free the D which we used */ + free_cover(D); + + /* Attempt to make the PLA matrix sparse */ + if (! skip_make_sparse) { + F = make_sparse(F, D1, R); + } + + /* + * Check to make sure function is actually smaller !! + * This can only happen because of the initial unravel. If we fail, + * then run the whole thing again without the unravel. + */ + if (Fsave->count < F->count) { + free_cover(F); + F = Fsave; + unwrap_onset = FALSE; + goto begin; + } else { + free_cover(Fsave); + } + + return F; +} diff --git a/benchmarks/benchmarks/espresso/espresso.h b/benchmarks/benchmarks/espresso/espresso.h new file mode 100644 index 0000000..38670e4 --- /dev/null +++ b/benchmarks/benchmarks/espresso/espresso.h @@ -0,0 +1,772 @@ +#if defined(USE_LOCH) && defined(_WIN32) +#pragma comment(lib, "loch.lib") +#endif + +/* + * espresso.h -- header file for Espresso-mv + */ + +#include "port.h" +#include "utility.h" +#include "sparse.h" +#include "mincov.h" + +#define ptime() util_cpu_time() +#define print_time(t) util_print_time(t) + +#ifdef IBM_WATC +#define void int +#include "short.h" +#endif + +#ifdef IBMPC /* set default options for IBM/PC */ +#define NO_INLINE +#define BPI 16 +#endif + +/*-----THIS USED TO BE set.h----- */ + +/* + * set.h -- definitions for packed arrays of bits + * + * This header file describes the data structures which comprise a + * facility for efficiently implementing packed arrays of bits + * (otherwise known as sets, cf. Pascal). + * + * A set is a vector of bits and is implemented here as an array of + * unsigned integers. The low order bits of set[0] give the index of + * the last word of set data. The higher order bits of set[0] are + * used to store data associated with the set. The set data is + * contained in elements set[1] ... set[LOOP(set)] as a packed bit + * array. + * + * A family of sets is a two-dimensional matrix of bits and is + * implemented with the data type "set_family". + * + * BPI == 32 and BPI == 16 have been tested and work. + */ + + +/* Define host machine characteristics of "unsigned int" */ +#ifndef BPI +#define BPI 32 /* # bits per integer */ +#endif + +#if BPI == 32 +#define LOGBPI 5 /* log(BPI)/log(2) */ +#else +#define LOGBPI 4 /* log(BPI)/log(2) */ +#endif + +/* Define the set type */ +typedef unsigned int *pset; + +/* Define the set family type -- an array of sets */ +typedef struct set_family { + int wsize; /* Size of each set in 'ints' */ + int sf_size; /* User declared set size */ + int capacity; /* Number of sets allocated */ + int count; /* The number of sets in the family */ + int active_count; /* Number of "active" sets */ + pset data; /* Pointer to the set data */ + struct set_family *next; /* For garbage collection */ +} set_family_t, *pset_family; + +/* Macros to set and test single elements */ +#define WHICH_WORD(element) (((element) >> LOGBPI) + 1) +#define WHICH_BIT(element) ((element) & (BPI-1)) + +/* # of ints needed to allocate a set with "size" elements */ +#if BPI == 32 +#define SET_SIZE(size) ((size) <= BPI ? 2 : (WHICH_WORD((size)-1) + 1)) +#else +#define SET_SIZE(size) ((size) <= BPI ? 3 : (WHICH_WORD((size)-1) + 2)) +#endif + +/* + * Three fields are maintained in the first word of the set + * LOOP is the index of the last word used for set data + * LOOPCOPY is the index of the last word in the set + * SIZE is available for general use (e.g., recording # elements in set) + * NELEM retrieves the number of elements in the set + */ +#define LOOP(set) (set[0] & 0x03ff) +#define PUTLOOP(set, i) (set[0] &= ~0x03ff, set[0] |= (i)) +#if BPI == 32 +#define LOOPCOPY(set) LOOP(set) +#define SIZE(set) (set[0] >> 16) +#define PUTSIZE(set, size) (set[0] &= 0xffff, set[0] |= ((size) << 16)) +#else +#define LOOPCOPY(set) (LOOP(set) + 1) +#define SIZE(set) (set[LOOP(set)+1]) +#define PUTSIZE(set, size) ((set[LOOP(set)+1]) = (size)) +#endif + +#define NELEM(set) (BPI * LOOP(set)) +#define LOOPINIT(size) ((size <= BPI) ? 1 : WHICH_WORD((size)-1)) + +/* + * FLAGS store general information about the set + */ +#define SET(set, flag) (set[0] |= (flag)) +#define RESET(set, flag) (set[0] &= ~ (flag)) +#define TESTP(set, flag) (set[0] & (flag)) + +/* Flag definitions are ... */ +#define PRIME 0x8000 /* cube is prime */ +#define NONESSEN 0x4000 /* cube cannot be essential prime */ +#define ACTIVE 0x2000 /* cube is still active */ +#define REDUND 0x1000 /* cube is redundant(at this point) */ +#define COVERED 0x0800 /* cube has been covered */ +#define RELESSEN 0x0400 /* cube is relatively essential */ + +/* Most efficient way to look at all members of a set family */ +#define foreach_set(R, last, p)\ + for(p=R->data,last=p+R->count*R->wsize;pwsize) +#define foreach_remaining_set(R, last, pfirst, p)\ + for(p=pfirst+R->wsize,last=R->data+R->count*R->wsize;pwsize) +#define foreach_active_set(R, last, p)\ + foreach_set(R,last,p) if (TESTP(p, ACTIVE)) + +/* Another way that also keeps the index of the current set member in i */ +#define foreachi_set(R, i, p)\ + for(p=R->data,i=0;icount;p+=R->wsize,i++) +#define foreachi_active_set(R, i, p)\ + foreachi_set(R,i,p) if (TESTP(p, ACTIVE)) + +/* Looping over all elements in a set: + * foreach_set_element(pset p, int i, unsigned val, int base) { + * . + * . + * . + * } + */ +#define foreach_set_element(p, i, val, base) \ + for(i = LOOP(p); i > 0; ) \ + for(val = p[i], base = --i << LOGBPI; val != 0; base++, val >>= 1) \ + if (val & 1) + +/* Return a pointer to a given member of a set family */ +#define GETSET(family, index) ((family)->data + (family)->wsize * (index)) + +/* Allocate and deallocate sets */ +#define set_new(size) set_clear(ALLOC(unsigned int, SET_SIZE(size)), size) +#define set_full(size) set_fill(ALLOC(unsigned int, SET_SIZE(size)), size) +#define set_save(r) set_copy(ALLOC(unsigned int, SET_SIZE(NELEM(r))), r) +#define set_free(r) FREE(r) + +/* Check for set membership, remove set element and insert set element */ +#define is_in_set(set, e) (set[WHICH_WORD(e)] & (1 << WHICH_BIT(e))) +#define set_remove(set, e) (set[WHICH_WORD(e)] &= ~ (1 << WHICH_BIT(e))) +#define set_insert(set, e) (set[WHICH_WORD(e)] |= 1 << WHICH_BIT(e)) + +/* Inline code substitution for those places that REALLY need it on a VAX */ +#ifdef NO_INLINE +#define INLINEset_copy(r, a) (void) set_copy(r,a) +#define INLINEset_clear(r, size) (void) set_clear(r, size) +#define INLINEset_fill(r, size) (void) set_fill(r, size) +#define INLINEset_and(r, a, b) (void) set_and(r, a, b) +#define INLINEset_or(r, a, b) (void) set_or(r, a, b) +#define INLINEset_diff(r, a, b) (void) set_diff(r, a, b) +#define INLINEset_ndiff(r, a, b, f) (void) set_ndiff(r, a, b, f) +#define INLINEset_xor(r, a, b) (void) set_xor(r, a, b) +#define INLINEset_xnor(r, a, b, f) (void) set_xnor(r, a, b, f) +#define INLINEset_merge(r, a, b, mask) (void) set_merge(r, a, b, mask) +#define INLINEsetp_implies(a, b, when_false) \ + if (! setp_implies(a,b)) when_false +#define INLINEsetp_disjoint(a, b, when_false) \ + if (! setp_disjoint(a,b)) when_false +#define INLINEsetp_equal(a, b, when_false) \ + if (! setp_equal(a,b)) when_false + +#else + +#define INLINEset_copy(r, a)\ + {register int i_=LOOPCOPY(a); do r[i_]=a[i_]; while (--i_>=0);} +#define INLINEset_clear(r, size)\ + {register int i_=LOOPINIT(size); *r=i_; do r[i_] = 0; while (--i_ > 0);} +#define INLINEset_fill(r, size)\ + {register int i_=LOOPINIT(size); *r=i_; \ + r[i_]=((unsigned int)(~0))>>(i_*BPI-size); while(--i_>0) r[i_]=~0;} +#define INLINEset_and(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] & b[i_]; while (--i_>0);} +#define INLINEset_or(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] | b[i_]; while (--i_>0);} +#define INLINEset_diff(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] & ~ b[i_]; while (--i_>0);} +#define INLINEset_ndiff(r, a, b, fullset)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = fullset[i_] & (a[i_] | ~ b[i_]); while (--i_>0);} +#ifdef IBM_WATC +#define INLINEset_xor(r, a, b) (void) set_xor(r, a, b) +#define INLINEset_xnor(r, a, b, f) (void) set_xnor(r, a, b, f) +#else +#define INLINEset_xor(r, a, b)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = a[i_] ^ b[i_]; while (--i_>0);} +#define INLINEset_xnor(r, a, b, fullset)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = fullset[i_] & ~ (a[i_] ^ b[i_]); while (--i_>0);} +#endif +#define INLINEset_merge(r, a, b, mask)\ + {register int i_=LOOP(a); PUTLOOP(r,i_);\ + do r[i_] = (a[i_]&mask[i_]) | (b[i_]&~mask[i_]); while (--i_>0);} +#define INLINEsetp_implies(a, b, when_false)\ + {register int i_=LOOP(a); do if (a[i_]&~b[i_]) break; while (--i_>0);\ + if (i_ != 0) when_false;} +#define INLINEsetp_disjoint(a, b, when_false)\ + {register int i_=LOOP(a); do if (a[i_]&b[i_]) break; while (--i_>0);\ + if (i_ != 0) when_false;} +#define INLINEsetp_equal(a, b, when_false)\ + {register int i_=LOOP(a); do if (a[i_]!=b[i_]) break; while (--i_>0);\ + if (i_ != 0) when_false;} + +#endif + +#if BPI == 32 +#define count_ones(v)\ + (bit_count[v & 255] + bit_count[(v >> 8) & 255]\ + + bit_count[(v >> 16) & 255] + bit_count[(v >> 24) & 255]) +#else +#define count_ones(v) (bit_count[v & 255] + bit_count[(v >> 8) & 255]) +#endif + +/* Table for efficient bit counting */ +extern int bit_count[256]; +/*----- END OF set.h ----- */ + +/* Define a boolean type */ +#define bool int +#define FALSE 0 +#define TRUE 1 +#define MAYBE 2 +#define print_bool(x) ((x) == 0 ? "FALSE" : ((x) == 1 ? "TRUE" : "MAYBE")) + +/* Map many cube/cover types/routines into equivalent set types/routines */ +#define pcube pset +#define new_cube() set_new(cube.size) +#define free_cube(r) set_free(r) +#define pcover pset_family +#define new_cover(i) sf_new(i, cube.size) +#define free_cover(r) sf_free(r) +#define free_cubelist(T) FREE(T[0]); FREE(T); + + +/* cost_t describes the cost of a cover */ +typedef struct cost_struct { + int cubes; /* number of cubes in the cover */ + int in; /* transistor count, binary-valued variables */ + int out; /* transistor count, output part */ + int mv; /* transistor count, multiple-valued vars */ + int total; /* total number of transistors */ + int primes; /* number of prime cubes */ +} cost_t, *pcost; + + +/* pair_t describes bit-paired variables */ +typedef struct pair_struct { + int cnt; + int *var1; + int *var2; +} pair_t, *ppair; + + +/* symbolic_list_t describes a single ".symbolic" line */ +typedef struct symbolic_list_struct { + int variable; + int pos; + struct symbolic_list_struct *next; +} symbolic_list_t; + + +/* symbolic_list_t describes a single ".symbolic" line */ +typedef struct symbolic_label_struct { + char *label; + struct symbolic_label_struct *next; +} symbolic_label_t; + + +/* symbolic_t describes a linked list of ".symbolic" lines */ +typedef struct symbolic_struct { + symbolic_list_t *symbolic_list; /* linked list of items */ + int symbolic_list_length; /* length of symbolic_list list */ + symbolic_label_t *symbolic_label; /* linked list of new names */ + int symbolic_label_length; /* length of symbolic_label list */ + struct symbolic_struct *next; +} symbolic_t; + + +/* PLA_t stores the logical representation of a PLA */ +typedef struct { + pcover F, D, R; /* on-set, off-set and dc-set */ + char *filename; /* filename */ + int pla_type; /* logical PLA format */ + pcube phase; /* phase to split into on-set and off-set */ + ppair pair; /* how to pair variables */ + char **label; /* labels for the columns */ + symbolic_t *symbolic; /* allow binary->symbolic mapping */ + symbolic_t *symbolic_output;/* allow symbolic output mapping */ +} PLA_t, *pPLA; + +#define equal(a,b) (strcmp(a,b) == 0) + +/* This is a hack which I wish I hadn't done, but too painful to change */ +#define CUBELISTSIZE(T) (((pcube *) T[1] - T) - 3) + +/* For documentation purposes */ +#define IN +#define OUT +#define INOUT + +/* The pla_type field describes the input and output format of the PLA */ +#define F_type 1 +#define D_type 2 +#define R_type 4 +#define PLEASURE_type 8 /* output format */ +#define EQNTOTT_type 16 /* output format algebraic eqns */ +#define KISS_type 128 /* output format kiss */ +#define CONSTRAINTS_type 256 /* output the constraints (numeric) */ +#define SYMBOLIC_CONSTRAINTS_type 512 /* output the constraints (symbolic) */ +#define FD_type (F_type | D_type) +#define FR_type (F_type | R_type) +#define DR_type (D_type | R_type) +#define FDR_type (F_type | D_type | R_type) + +/* Definitions for the debug variable */ +#define COMPL 0x0001 +#define ESSEN 0x0002 +#define EXPAND 0x0004 +#define EXPAND1 0x0008 +#define GASP 0x0010 +#define IRRED 0x0020 +#define REDUCE 0x0040 +#define REDUCE1 0x0080 +#define SPARSE 0x0100 +#define TAUT 0x0200 +#define EXACT 0x0400 +#define MINCOV 0x0800 +#define MINCOV1 0x1000 +#define SHARP 0x2000 +#define IRRED1 0x4000 + +#define VERSION\ + "UC Berkeley, Espresso Version #2.3, Release date 01/31/88" + +/* Define constants used for recording program statistics */ +#define TIME_COUNT 16 +#define READ_TIME 0 +#define COMPL_TIME 1 +#define ONSET_TIME 2 +#define ESSEN_TIME 3 +#define EXPAND_TIME 4 +#define IRRED_TIME 5 +#define REDUCE_TIME 6 +#define GEXPAND_TIME 7 +#define GIRRED_TIME 8 +#define GREDUCE_TIME 9 +#define PRIMES_TIME 10 +#define MINCOV_TIME 11 +#define MV_REDUCE_TIME 12 +#define RAISE_IN_TIME 13 +#define VERIFY_TIME 14 +#define WRITE_TIME 15 + + +/* For those who like to think about PLAs, macros to get at inputs/outputs */ +#define NUMINPUTS cube.num_binary_vars +#define NUMOUTPUTS cube.part_size[cube.num_vars - 1] + +#define POSITIVE_PHASE(pos)\ + (is_in_set(PLA->phase, cube.first_part[cube.output]+pos) != 0) + +#define INLABEL(var) PLA->label[cube.first_part[var] + 1] +#define OUTLABEL(pos) PLA->label[cube.first_part[cube.output] + pos] + +#define GETINPUT(c, pos)\ + ((c[WHICH_WORD(2*pos)] >> WHICH_BIT(2*pos)) & 3) +#define GETOUTPUT(c, pos)\ + (is_in_set(c, cube.first_part[cube.output] + pos) != 0) + +#define PUTINPUT(c, pos, value)\ + c[WHICH_WORD(2*pos)] = (c[WHICH_WORD(2*pos)] & ~(3 << WHICH_BIT(2*pos)))\ + | (value << WHICH_BIT(2*pos)) +#define PUTOUTPUT(c, pos, value)\ + c[WHICH_WORD(pos)] = (c[WHICH_WORD(pos)] & (1 << WHICH_BIT(pos)))\ + | (value << WHICH_BIT(pos)) + +#define TWO 3 +#define DASH 3 +#define ONE 2 +#define ZERO 1 + + +#define EXEC(fct, name, S)\ + {long t=ptime();fct;if(trace)print_trace(S,name,ptime()-t);} +#define EXEC_S(fct, name, S)\ + {long t=ptime();fct;if(summary)print_trace(S,name,ptime()-t);} +#define EXECUTE(fct,i,S,cost)\ + {long t=ptime();fct;totals(t,i,S,&(cost));} + +/* + * Global Variable Declarations + */ + +extern unsigned int debug; /* debug parameter */ +extern bool verbose_debug; /* -v: whether to print a lot */ +extern char *total_name[TIME_COUNT]; /* basic function names */ +extern long total_time[TIME_COUNT]; /* time spent in basic fcts */ +extern int total_calls[TIME_COUNT]; /* # calls to each fct */ + +extern bool echo_comments; /* turned off by -eat option */ +extern bool echo_unknown_commands; /* always true ?? */ +extern bool force_irredundant; /* -nirr command line option */ +extern bool skip_make_sparse; +extern bool kiss; /* -kiss command line option */ +extern bool pos; /* -pos command line option */ +extern bool print_solution; /* -x command line option */ +extern bool recompute_onset; /* -onset command line option */ +extern bool remove_essential; /* -ness command line option */ +extern bool single_expand; /* -fast command line option */ +extern bool summary; /* -s command line option */ +extern bool trace; /* -t command line option */ +extern bool unwrap_onset; /* -nunwrap command line option */ +extern bool use_random_order; /* -random command line option */ +extern bool use_super_gasp; /* -strong command line option */ +extern char *filename; /* filename PLA was read from */ +extern bool debug_exact_minimization; /* dumps info for -do exact */ + + +/* + * pla_types are the input and output types for reading/writing a PLA + */ +struct pla_types_struct { + char *key; + int value; +}; + + +/* + * The cube structure is a global structure which contains information + * on how a set maps into a cube -- i.e., number of parts per variable, + * number of variables, etc. Also, many fields are pre-computed to + * speed up various primitive operations. + */ +#define CUBE_TEMP 10 + +struct cube_struct { + int size; /* set size of a cube */ + int num_vars; /* number of variables in a cube */ + int num_binary_vars; /* number of binary variables */ + int *first_part; /* first element of each variable */ + int *last_part; /* first element of each variable */ + int *part_size; /* number of elements in each variable */ + int *first_word; /* first word for each variable */ + int *last_word; /* last word for each variable */ + pset binary_mask; /* Mask to extract binary variables */ + pset mv_mask; /* mask to get mv parts */ + pset *var_mask; /* mask to extract a variable */ + pset *temp; /* an array of temporary sets */ + pset fullset; /* a full cube */ + pset emptyset; /* an empty cube */ + unsigned int inmask; /* mask to get odd word of binary part */ + int inword; /* which word number for above */ + int *sparse; /* should this variable be sparse? */ + int num_mv_vars; /* number of multiple-valued variables */ + int output; /* which variable is "output" (-1 if none) */ +}; + +struct cdata_struct { + int *part_zeros; /* count of zeros for each element */ + int *var_zeros; /* count of zeros for each variable */ + int *parts_active; /* number of "active" parts for each var */ + bool *is_unate; /* indicates given var is unate */ + int vars_active; /* number of "active" variables */ + int vars_unate; /* number of unate variables */ + int best; /* best "binate" variable */ +}; + + +extern struct pla_types_struct pla_types[]; +extern struct cube_struct cube, temp_cube_save; +extern struct cdata_struct cdata, temp_cdata_save; + +#ifdef lint +#define DISJOINT 0x5555 +#else +#if BPI == 32 +#define DISJOINT 0x55555555 +#else +#define DISJOINT 0x5555 +#endif +#endif + +/* function declarations */ + +/* cofactor.c */ extern int binate_split_select(); +/* cofactor.c */ extern pcover cubeunlist(); +/* cofactor.c */ extern pcube *cofactor(); +/* cofactor.c */ extern pcube *cube1list(); +/* cofactor.c */ extern pcube *cube2list(); +/* cofactor.c */ extern pcube *cube3list(); +/* cofactor.c */ extern pcube *scofactor(); +/* cofactor.c */ extern void massive_count(); +/* compl.c */ extern pcover complement(); +/* compl.c */ extern pcover simplify(); +/* compl.c */ extern void simp_comp(); +/* contain.c */ extern int d1_rm_equal(); +/* contain.c */ extern int rm2_contain(); +/* contain.c */ extern int rm2_equal(); +/* contain.c */ extern int rm_contain(); +/* contain.c */ extern int rm_equal(); +/* contain.c */ extern int rm_rev_contain(); +/* contain.c */ extern pset *sf_list(); +/* contain.c */ extern pset *sf_sort(); +/* contain.c */ extern pset_family d1merge(); +/* contain.c */ extern pset_family dist_merge(); +/* contain.c */ extern pset_family sf_contain(); +/* contain.c */ extern pset_family sf_dupl(); +/* contain.c */ extern pset_family sf_ind_contain(); +/* contain.c */ extern pset_family sf_ind_unlist(); +/* contain.c */ extern pset_family sf_merge(); +/* contain.c */ extern pset_family sf_rev_contain(); +/* contain.c */ extern pset_family sf_union(); +/* contain.c */ extern pset_family sf_unlist(); +/* cubestr.c */ extern void cube_setup(); +/* cubestr.c */ extern void restore_cube_struct(); +/* cubestr.c */ extern void save_cube_struct(); +/* cubestr.c */ extern void setdown_cube(); +/* cvrin.c */ extern PLA_labels(); +/* cvrin.c */ extern char *get_word(); +/* cvrin.c */ extern int label_index(); +/* cvrin.c */ extern int read_pla(); +/* cvrin.c */ extern int read_symbolic(); +/* cvrin.c */ extern pPLA new_PLA(); +/* cvrin.c */ extern void PLA_summary(); +/* cvrin.c */ extern void free_PLA(); +/* cvrin.c */ extern void parse_pla(); +/* cvrin.c */ extern void read_cube(); +/* cvrin.c */ extern void skip_line(); +/* cvrm.c */ extern foreach_output_function(); +/* cvrm.c */ extern int cubelist_partition(); +/* cvrm.c */ extern int so_both_do_espresso(); +/* cvrm.c */ extern int so_both_do_exact(); +/* cvrm.c */ extern int so_both_save(); +/* cvrm.c */ extern int so_do_espresso(); +/* cvrm.c */ extern int so_do_exact(); +/* cvrm.c */ extern int so_save(); +/* cvrm.c */ extern pcover cof_output(); +/* cvrm.c */ extern pcover lex_sort(); +/* cvrm.c */ extern pcover mini_sort(); +/* cvrm.c */ extern pcover random_order(); +/* cvrm.c */ extern pcover size_sort(); +/* cvrm.c */ extern pcover sort_reduce(); +/* cvrm.c */ extern pcover uncof_output(); +/* cvrm.c */ extern pcover unravel(); +/* cvrm.c */ extern pcover unravel_range(); +/* cvrm.c */ extern void so_both_espresso(); +/* cvrm.c */ extern void so_espresso(); +/* cvrmisc.c */ extern char *fmt_cost(); +/* cvrmisc.c */ extern char *print_cost(); +/* cvrmisc.c */ extern char *strsav(); +/* cvrmisc.c */ extern void copy_cost(); +/* cvrmisc.c */ extern void cover_cost(); +/* cvrmisc.c */ extern void fatal(); +/* cvrmisc.c */ extern void print_trace(); +/* cvrmisc.c */ extern void size_stamp(); +/* cvrmisc.c */ extern void totals(); +/* cvrout.c */ extern char *fmt_cube(); +/* cvrout.c */ extern char *fmt_expanded_cube(); +/* cvrout.c */ extern char *pc1(); +/* cvrout.c */ extern char *pc2(); +/* cvrout.c */ extern char *pc3(); +/* cvrout.c */ extern int makeup_labels(); +/* cvrout.c */ extern kiss_output(); +/* cvrout.c */ extern kiss_print_cube(); +/* cvrout.c */ extern output_symbolic_constraints(); +/* cvrout.c */ extern void cprint(); +/* cvrout.c */ extern void debug1_print(); +/* cvrout.c */ extern void debug_print(); +/* cvrout.c */ extern void eqn_output(); +/* cvrout.c */ extern void fpr_header(); +/* cvrout.c */ extern void fprint_pla(); +/* cvrout.c */ extern void pls_group(); +/* cvrout.c */ extern void pls_label(); +/* cvrout.c */ extern void pls_output(); +/* cvrout.c */ extern void print_cube(); +/* cvrout.c */ extern void print_expanded_cube(); +/* cvrout.c */ extern void sf_debug_print(); +/* equiv.c */ extern find_equiv_outputs(); +/* equiv.c */ extern int check_equiv(); +/* espresso.c */ extern pcover espresso(); +/* essen.c */ extern bool essen_cube(); +/* essen.c */ extern pcover cb_consensus(); +/* essen.c */ extern pcover cb_consensus_dist0(); +/* essen.c */ extern pcover essential(); +/* exact.c */ extern pcover minimize_exact(); +/* exact.c */ extern pcover minimize_exact_literals(); +/* expand.c */ extern bool feasibly_covered(); +/* expand.c */ extern int most_frequent(); +/* expand.c */ extern pcover all_primes(); +/* expand.c */ extern pcover expand(); +/* expand.c */ extern pcover find_all_primes(); +/* expand.c */ extern void elim_lowering(); +/* expand.c */ extern void essen_parts(); +/* expand.c */ extern void essen_raising(); +/* expand.c */ extern void expand1(); +/* expand.c */ extern void mincov(); +/* expand.c */ extern void select_feasible(); +/* expand.c */ extern void setup_BB_CC(); +/* gasp.c */ extern pcover expand_gasp(); +/* gasp.c */ extern pcover irred_gasp(); +/* gasp.c */ extern pcover last_gasp(); +/* gasp.c */ extern pcover super_gasp(); +/* gasp.c */ extern void expand1_gasp(); +/* getopt.c */ extern int getopt(); +/* hack.c */ extern find_dc_inputs(); +/* hack.c */ extern find_inputs(); +/* hack.c */ extern form_bitvector(); +/* hack.c */ extern map_dcset(); +/* hack.c */ extern map_output_symbolic(); +/* hack.c */ extern map_symbolic(); +/* hack.c */ extern pcover map_symbolic_cover(); +/* hack.c */ extern symbolic_hack_labels(); +/* irred.c */ extern bool cube_is_covered(); +/* irred.c */ extern bool taut_special_cases(); +/* irred.c */ extern bool tautology(); +/* irred.c */ extern pcover irredundant(); +/* irred.c */ extern void mark_irredundant(); +/* irred.c */ extern void irred_split_cover(); +/* irred.c */ extern sm_matrix *irred_derive_table(); +/* map.c */ extern pset minterms(); +/* map.c */ extern void explode(); +/* map.c */ extern void map(); +/* opo.c */ extern output_phase_setup(); +/* opo.c */ extern pPLA set_phase(); +/* opo.c */ extern pcover opo(); +/* opo.c */ extern pcube find_phase(); +/* opo.c */ extern pset_family find_covers(); +/* opo.c */ extern pset_family form_cover_table(); +/* opo.c */ extern pset_family opo_leaf(); +/* opo.c */ extern pset_family opo_recur(); +/* opo.c */ extern void opoall(); +/* opo.c */ extern void phase_assignment(); +/* opo.c */ extern void repeated_phase_assignment(); +/* pair.c */ extern generate_all_pairs(); +/* pair.c */ extern int **find_pairing_cost(); +/* pair.c */ extern int find_best_cost(); +/* pair.c */ extern int greedy_best_cost(); +/* pair.c */ extern int minimize_pair(); +/* pair.c */ extern int pair_free(); +/* pair.c */ extern pair_all(); +/* pair.c */ extern pcover delvar(); +/* pair.c */ extern pcover pairvar(); +/* pair.c */ extern ppair pair_best_cost(); +/* pair.c */ extern ppair pair_new(); +/* pair.c */ extern ppair pair_save(); +/* pair.c */ extern print_pair(); +/* pair.c */ extern void find_optimal_pairing(); +/* pair.c */ extern void set_pair(); +/* pair.c */ extern void set_pair1(); +/* primes.c */ extern pcover primes_consensus(); +/* reduce.c */ extern bool sccc_special_cases(); +/* reduce.c */ extern pcover reduce(); +/* reduce.c */ extern pcube reduce_cube(); +/* reduce.c */ extern pcube sccc(); +/* reduce.c */ extern pcube sccc_cube(); +/* reduce.c */ extern pcube sccc_merge(); +/* set.c */ extern bool set_andp(); +/* set.c */ extern bool set_orp(); +/* set.c */ extern bool setp_disjoint(); +/* set.c */ extern bool setp_empty(); +/* set.c */ extern bool setp_equal(); +/* set.c */ extern bool setp_full(); +/* set.c */ extern bool setp_implies(); +/* set.c */ extern char *pbv1(); +/* set.c */ extern char *ps1(); +/* set.c */ extern int *sf_count(); +/* set.c */ extern int *sf_count_restricted(); +/* set.c */ extern int bit_index(); +/* set.c */ extern int set_dist(); +/* set.c */ extern int set_ord(); +/* set.c */ extern void set_adjcnt(); +/* set.c */ extern pset set_and(); +/* set.c */ extern pset set_clear(); +/* set.c */ extern pset set_copy(); +/* set.c */ extern pset set_diff(); +/* set.c */ extern pset set_fill(); +/* set.c */ extern pset set_merge(); +/* set.c */ extern pset set_or(); +/* set.c */ extern pset set_xor(); +/* set.c */ extern pset sf_and(); +/* set.c */ extern pset sf_or(); +/* set.c */ extern pset_family sf_active(); +/* set.c */ extern pset_family sf_addcol(); +/* set.c */ extern pset_family sf_addset(); +/* set.c */ extern pset_family sf_append(); +/* set.c */ extern pset_family sf_bm_read(); +/* set.c */ extern pset_family sf_compress(); +/* set.c */ extern pset_family sf_copy(); +/* set.c */ extern pset_family sf_copy_col(); +/* set.c */ extern pset_family sf_delc(); +/* set.c */ extern pset_family sf_delcol(); +/* set.c */ extern pset_family sf_inactive(); +/* set.c */ extern pset_family sf_join(); +/* set.c */ extern pset_family sf_new(); +/* set.c */ extern pset_family sf_permute(); +/* set.c */ extern pset_family sf_read(); +/* set.c */ extern pset_family sf_save(); +/* set.c */ extern pset_family sf_transpose(); +/* set.c */ extern void set_write(); +/* set.c */ extern void sf_bm_print(); +/* set.c */ extern void sf_cleanup(); +/* set.c */ extern void sf_delset(); +/* set.c */ extern void sf_free(); +/* set.c */ extern void sf_print(); +/* set.c */ extern void sf_write(); +/* setc.c */ extern bool ccommon(); +/* setc.c */ extern bool cdist0(); +/* setc.c */ extern bool full_row(); +/* setc.c */ extern int ascend(); +/* setc.c */ extern int cactive(); +/* setc.c */ extern int cdist(); +/* setc.c */ extern int cdist01(); +/* setc.c */ extern int cvolume(); +/* setc.c */ extern int d1_order(); +/* setc.c */ extern int d1_order_size(); +/* setc.c */ extern int desc1(); +/* setc.c */ extern int descend(); +/* setc.c */ extern int lex_order(); +/* setc.c */ extern int lex_order1(); +/* setc.c */ extern pset force_lower(); +/* setc.c */ extern void consensus(); +/* sharp.c */ extern pcover cb1_dsharp(); +/* sharp.c */ extern pcover cb_dsharp(); +/* sharp.c */ extern pcover cb_recur_dsharp(); +/* sharp.c */ extern pcover cb_recur_sharp(); +/* sharp.c */ extern pcover cb_sharp(); +/* sharp.c */ extern pcover cv_dsharp(); +/* sharp.c */ extern pcover cv_intersect(); +/* sharp.c */ extern pcover cv_sharp(); +/* sharp.c */ extern pcover dsharp(); +/* sharp.c */ extern pcover make_disjoint(); +/* sharp.c */ extern pcover sharp(); +/* sminterf.c */pset do_sm_minimum_cover(); +/* sparse.c */ extern pcover make_sparse(); +/* sparse.c */ extern pcover mv_reduce(); +/* ucbqsort.c extern qsort(); */ +/* ucbqsort.c */ extern qst(); +/* unate.c */ extern pcover find_all_minimal_covers_petrick(); +/* unate.c */ extern pcover map_cover_to_unate(); +/* unate.c */ extern pcover map_unate_to_cover(); +/* unate.c */ extern pset_family exact_minimum_cover(); +/* unate.c */ extern pset_family gen_primes(); +/* unate.c */ extern pset_family unate_compl(); +/* unate.c */ extern pset_family unate_complement(); +/* unate.c */ extern pset_family unate_intersect(); +/* verify.c */ extern PLA_permute(); +/* verify.c */ extern bool PLA_verify(); +/* verify.c */ extern bool check_consistency(); +/* verify.c */ extern bool verify(); diff --git a/benchmarks/benchmarks/espresso/essen.c b/benchmarks/benchmarks/espresso/essen.c new file mode 100644 index 0000000..52a1655 --- /dev/null +++ b/benchmarks/benchmarks/espresso/essen.c @@ -0,0 +1,170 @@ +/* + module: essen.c + purpose: Find essential primes in a multiple-valued function +*/ + +#include "espresso.h" + +/* + essential -- return a cover consisting of the cubes of F which are + essential prime implicants (with respect to F u D); Further, remove + these cubes from the ON-set F, and add them to the OFF-set D. + + Sometimes EXPAND can determine that a cube is not an essential prime. + If so, it will set the "NONESSEN" flag in the cube. + + We count on IRREDUNDANT to have set the flag RELESSEN to indicate + that a prime was relatively essential (i.e., covers some minterm + not contained in any other prime in the current cover), or to have + reset the flag to indicate that a prime was relatively redundant + (i.e., all minterms covered by other primes in the current cover). + Of course, after executing irredundant, all of the primes in the + cover are relatively essential, but we can mark the primes which + were redundant at the start of irredundant and avoid an extra check + on these primes for essentiality. +*/ + +pcover essential(Fp, Dp) +IN pcover *Fp, *Dp; +{ + register pcube last, p; + pcover E, F = *Fp, D = *Dp; + + /* set all cubes in F active */ + (void) sf_active(F); + + /* Might as well start out with some cubes in E */ + E = new_cover(10); + + foreach_set(F, last, p) { + /* don't test a prime which EXPAND says is nonessential */ + if (! TESTP(p, NONESSEN)) { + /* only test a prime which was relatively essential */ + if (TESTP(p, RELESSEN)) { + /* Check essentiality */ + if (essen_cube(F, D, p)) { + if (debug & ESSEN) + printf("ESSENTIAL: %s\n", pc1(p)); + E = sf_addset(E, p); + RESET(p, ACTIVE); + F->active_count--; + } + } + } + } + + *Fp = sf_inactive(F); /* delete the inactive cubes from F */ + *Dp = sf_join(D, E); /* add the essentials to D */ + sf_free(D); + return E; +} + +/* + essen_cube -- check if a single cube is essential or not + + The prime c is essential iff + + consensus((F u D) # c, c) u D + + does not contain c. +*/ +bool essen_cube(F, D, c) +IN pcover F, D; +IN pcube c; +{ + pcover H, FD; + pcube *H1; + bool essen; + + /* Append F and D together, and take the sharp-consensus with c */ + FD = sf_join(F, D); + H = cb_consensus(FD, c); + free_cover(FD); + + /* Add the don't care set, and see if this covers c */ + H1 = cube2list(H, D); + essen = ! cube_is_covered(H1, c); + free_cubelist(H1); + + free_cover(H); + return essen; +} + + +/* + * cb_consensus -- compute consensus(T # c, c) + */ +pcover cb_consensus(T, c) +register pcover T; +register pcube c; +{ + register pcube temp, last, p; + register pcover R; + + R = new_cover(T->count*2); + temp = new_cube(); + foreach_set(T, last, p) { + if (p != c) { + switch (cdist01(p, c)) { + case 0: + /* distance-0 needs special care */ + R = cb_consensus_dist0(R, p, c); + break; + + case 1: + /* distance-1 is easy because no sharping required */ + consensus(temp, p, c); + R = sf_addset(R, temp); + break; + } + } + } + set_free(temp); + return R; +} + + +/* + * form the sharp-consensus for p and c when they intersect + * What we are forming is consensus(p # c, c). + */ +pcover cb_consensus_dist0(R, p, c) +pcover R; +register pcube p, c; +{ + int var; + bool got_one; + register pcube temp, mask; + register pcube p_diff_c=cube.temp[0], p_and_c=cube.temp[1]; + + /* If c contains p, then this gives us no information for essential test */ + if (setp_implies(p, c)) { + return R; + } + + /* For the multiple-valued variables */ + temp = new_cube(); + got_one = FALSE; + INLINEset_diff(p_diff_c, p, c); + INLINEset_and(p_and_c, p, c); + + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + /* Check if c(var) is contained in p(var) -- if so, no news */ + mask = cube.var_mask[var]; + if (! setp_disjoint(p_diff_c, mask)) { + INLINEset_merge(temp, c, p_and_c, mask); + R = sf_addset(R, temp); + got_one = TRUE; + } + } + + /* if no cube so far, add one for the intersection */ + if (! got_one && cube.num_binary_vars > 0) { + /* Add a single cube for the intersection of p and c */ + INLINEset_and(temp, p, c); + R = sf_addset(R, temp); + } + + set_free(temp); + return R; +} diff --git a/benchmarks/benchmarks/espresso/exact.c b/benchmarks/benchmarks/espresso/exact.c new file mode 100644 index 0000000..336a3ff --- /dev/null +++ b/benchmarks/benchmarks/espresso/exact.c @@ -0,0 +1,166 @@ +#include "espresso.h" +#include + +static void dump_irredundant(); +static pcover do_minimize(); + + +/* + * minimize_exact -- main entry point for exact minimization + * + * Global flags which affect this routine are: + * + * debug + * skip_make_sparse + */ + +pcover +minimize_exact(F, D, R, exact_cover) +pcover F, D, R; +int exact_cover; +{ + return do_minimize(F, D, R, exact_cover, /*weighted*/ 0); +} + + +pcover +minimize_exact_literals(F, D, R, exact_cover) +pcover F, D, R; +int exact_cover; +{ + return do_minimize(F, D, R, exact_cover, /*weighted*/ 1); +} + + + +static pcover +do_minimize(F, D, R, exact_cover, weighted) +pcover F, D, R; +int exact_cover; +int weighted; +{ + pcover newF, E, Rt, Rp; + pset p, last; + int heur, level, *weights; + sm_matrix *table; + sm_row *cover; + sm_element *pe; + int debug_save = debug; + + if (debug & EXACT) { + debug |= (IRRED | MINCOV); + } +#if defined(sun) || defined(bsd4_2) /* hack ... */ + if (debug & MINCOV) { +// setlinebuf(stdout); + } +#endif + level = (debug & MINCOV) ? 4 : 0; + heur = ! exact_cover; + + /* Generate all prime implicants */ + EXEC(F = primes_consensus(cube2list(F, D)), "PRIMES ", F); + + /* Setup the prime implicant table */ + EXEC(irred_split_cover(F, D, &E, &Rt, &Rp), "ESSENTIALS ", E); + EXEC(table = irred_derive_table(D, E, Rp), "PI-TABLE ", Rp); + + /* Solve either a weighted or nonweighted covering problem */ + if (weighted) { + /* correct only for all 2-valued variables */ + weights = ALLOC(int, F->count); + foreach_set(Rp, last, p) { + weights[SIZE(p)] = cube.size - set_ord(p); + } + } else { + weights = NIL(int); + } + EXEC(cover=sm_minimum_cover(table,weights,heur,level), "MINCOV ", F); + if (weights != 0) { + FREE(weights); + } + + if (debug & EXACT) { + dump_irredundant(E, Rt, Rp, table); + } + + /* Form the result cover */ + newF = new_cover(100); + foreach_set(E, last, p) { + newF = sf_addset(newF, p); + } + sm_foreach_row_element(cover, pe) { + newF = sf_addset(newF, GETSET(F, pe->col_num)); + } + + free_cover(E); + free_cover(Rt); + free_cover(Rp); + sm_free(table); + sm_row_free(cover); + free_cover(F); + + /* Attempt to make the results more sparse */ + debug &= ~ (IRRED | SHARP | MINCOV); + if (! skip_make_sparse && R != 0) { + newF = make_sparse(newF, D, R); + } + + debug = debug_save; + return newF; +} + +static void +dump_irredundant(E, Rt, Rp, table) +pcover E, Rt, Rp; +sm_matrix *table; +{ + FILE *fp_pi_table, *fp_primes; + pPLA PLA; + pset last, p; + char *file; + + if (filename == 0 || strcmp(filename, "(stdin)") == 0) { + fp_pi_table = fp_primes = stdout; + } else { + file = ALLOC(char, strlen(filename)+20); + (void) sprintf(file, "%s.primes", filename); + if ((fp_primes = fopen(file, "w")) == NULL) { + fprintf(stderr, "espresso: Unable to open %s\n", file); + fp_primes = stdout; + } + (void) sprintf(file, "%s.pi", filename); + if ((fp_pi_table = fopen(file, "w")) == NULL) { + fprintf(stderr, "espresso: Unable to open %s\n", file); + fp_pi_table = stdout; + } + FREE(file); + } + + PLA = new_PLA(); + PLA_labels(PLA); + + fpr_header(fp_primes, PLA, F_type); + free_PLA(PLA); + + (void) fprintf(fp_primes, "# Essential primes are\n"); + foreach_set(E, last, p) { + (void) fprintf(fp_primes, "%s\n", pc1(p)); + } + fprintf(fp_primes, "# Totally redundant primes are\n"); + foreach_set(Rt, last, p) { + (void) fprintf(fp_primes, "%s\n", pc1(p)); + } + fprintf(fp_primes, "# Partially redundant primes are\n"); + foreach_set(Rp, last, p) { + (void) fprintf(fp_primes, "%s\n", pc1(p)); + } + if (fp_primes != stdout) { + (void) fclose(fp_primes); + } + + sm_write(fp_pi_table, table); + if (fp_pi_table != stdout) { + (void) fclose(fp_pi_table); + } +} diff --git a/benchmarks/benchmarks/espresso/expand.c b/benchmarks/benchmarks/espresso/expand.c new file mode 100644 index 0000000..8eb7239 --- /dev/null +++ b/benchmarks/benchmarks/espresso/expand.c @@ -0,0 +1,680 @@ +/* + module: expand.c + purpose: Perform the Espresso-II Expansion Step + + The idea is to take each nonprime cube of the on-set and expand it + into a prime implicant such that we can cover as many other cubes + of the on-set. If no cube of the on-set can be covered, then we + expand each cube into a large prime implicant by transforming the + problem into a minimum covering problem which is solved by the + heuristics of minimum_cover. + + These routines revolve around having a representation of the + OFF-set. (In contrast to the Espresso-II manuscript, we do NOT + require an "unwrapped" version of the OFF-set). + + Some conventions on variable names: + + SUPER_CUBE is the supercube of all cubes which can be covered + by an expansion of the cube being expanded + + OVEREXPANDED_CUBE is the cube which would result from expanding + all parts which can expand individually of the cube being expanded + + RAISE is the current expansion of the current cube + + FREESET is the set of parts which haven't been raised or lowered yet. + + INIT_LOWER is a set of parts to be removed from the free parts before + starting the expansion +*/ + +#include "espresso.h" + +/* + expand -- expand each nonprime cube of F into a prime implicant + + If nonsparse is true, only the non-sparse variables will be expanded; + this is done by forcing all of the sparse variables out of the free set. +*/ + +pcover expand(F, R, nonsparse) +INOUT pcover F; +IN pcover R; +IN bool nonsparse; /* expand non-sparse variables only */ +{ + register pcube last, p; + pcube RAISE, FREESET, INIT_LOWER, SUPER_CUBE, OVEREXPANDED_CUBE; + int var, num_covered; + bool change; + + /* Order the cubes according to "chewing-away from the edges" of mini */ + if (use_random_order) + F = random_order(F); + else + F = mini_sort(F, ascend); + + /* Allocate memory for variables needed by expand1() */ + RAISE = new_cube(); + FREESET = new_cube(); + INIT_LOWER = new_cube(); + SUPER_CUBE = new_cube(); + OVEREXPANDED_CUBE = new_cube(); + + /* Setup the initial lowering set (differs only for nonsparse) */ + if (nonsparse) + for(var = 0; var < cube.num_vars; var++) + if (cube.sparse[var]) + (void) set_or(INIT_LOWER, INIT_LOWER, cube.var_mask[var]); + + /* Mark all cubes as not covered, and maybe essential */ + foreach_set(F, last, p) { + RESET(p, COVERED); + RESET(p, NONESSEN); + } + + /* Try to expand each nonprime and noncovered cube */ + foreach_set(F, last, p) { + /* do not expand if PRIME or if covered by previous expansion */ + if (! TESTP(p, PRIME) && ! TESTP(p, COVERED)) { + + /* expand the cube p, result is RAISE */ + expand1(R, F, RAISE, FREESET, OVEREXPANDED_CUBE, SUPER_CUBE, + INIT_LOWER, &num_covered, p); + if (debug & EXPAND) + printf("EXPAND: %s (covered %d)\n", pc1(p), num_covered); + (void) set_copy(p, RAISE); + SET(p, PRIME); + RESET(p, COVERED); /* not really necessary */ + + /* See if we generated an inessential prime */ + if (num_covered == 0 && ! setp_equal(p, OVEREXPANDED_CUBE)) { + SET(p, NONESSEN); + } + } + } + + /* Delete any cubes of F which became covered during the expansion */ + F->active_count = 0; + change = FALSE; + foreach_set(F, last, p) { + if (TESTP(p, COVERED)) { + RESET(p, ACTIVE); + change = TRUE; + } else { + SET(p, ACTIVE); + F->active_count++; + } + } + if (change) + F = sf_inactive(F); + + free_cube(RAISE); + free_cube(FREESET); + free_cube(INIT_LOWER); + free_cube(SUPER_CUBE); + free_cube(OVEREXPANDED_CUBE); + return F; +} + +/* + expand1 -- Expand a single cube against the OFF-set +*/ +void expand1(BB, CC, RAISE, FREESET, OVEREXPANDED_CUBE, SUPER_CUBE, + INIT_LOWER, num_covered, c) +pcover BB; /* Blocking matrix (OFF-set) */ +pcover CC; /* Covering matrix (ON-set) */ +pcube RAISE; /* The current parts which have been raised */ +pcube FREESET; /* The current parts which are free */ +pcube OVEREXPANDED_CUBE; /* Overexpanded cube of c */ +pcube SUPER_CUBE; /* Supercube of all cubes of CC we cover */ +pcube INIT_LOWER; /* Parts to initially remove from FREESET */ +int *num_covered; /* Number of cubes of CC which are covered */ +pcube c; /* The cube to be expanded */ +{ + int bestindex; + + if (debug & EXPAND1) + printf("\nEXPAND1: \t%s\n", pc1(c)); + + /* initialize BB and CC */ + SET(c, PRIME); /* don't try to cover ourself */ + setup_BB_CC(BB, CC); + + /* initialize count of # cubes covered, and the supercube of them */ + *num_covered = 0; + (void) set_copy(SUPER_CUBE, c); + + /* Initialize the lowering, raising and unassigned sets */ + (void) set_copy(RAISE, c); + (void) set_diff(FREESET, cube.fullset, RAISE); + + /* If some parts are forced into lowering set, remove them */ + if (! setp_empty(INIT_LOWER)) { + (void) set_diff(FREESET, FREESET, INIT_LOWER); + elim_lowering(BB, CC, RAISE, FREESET); + } + + /* Determine what can be raised, and return the over-expanded cube */ + essen_parts(BB, CC, RAISE, FREESET); + (void) set_or(OVEREXPANDED_CUBE, RAISE, FREESET); + + /* While there are still cubes which can be covered, cover them ! */ + if (CC->active_count > 0) { + select_feasible(BB, CC, RAISE, FREESET, SUPER_CUBE, num_covered); + } + + /* While there are still cubes covered by the overexpanded cube ... */ + while (CC->active_count > 0) { + bestindex = most_frequent(CC, FREESET); + set_insert(RAISE, bestindex); + set_remove(FREESET, bestindex); + essen_parts(BB, CC, RAISE, FREESET); + } + + /* Finally, when all else fails, choose the largest possible prime */ + /* We will loop only if we decide unravelling OFF-set is too expensive */ + while (BB->active_count > 0) { + mincov(BB, RAISE, FREESET); + } + + /* Raise any remaining free coordinates */ + (void) set_or(RAISE, RAISE, FREESET); +} + +/* + essen_parts -- determine which parts are forced into the lowering + set to insure that the cube be orthognal to the OFF-set. + + If any cube of the OFF-set is distance 1 from the raising cube, + then we must lower all parts of the conflicting variable. (If the + cube is distance 0, we detect this error here.) + + If there are essentially lowered parts, we can remove from consideration + any cubes of the OFF-set which are more than distance 1 from the + overexpanded cube of RAISE. +*/ + +void essen_parts(BB, CC, RAISE, FREESET) +pcover BB, CC; +pcube RAISE, FREESET; +{ + register pcube p, r = RAISE; + pcube lastp, xlower = cube.temp[0]; + int dist; + + (void) set_copy(xlower, cube.emptyset); + + foreach_active_set(BB, lastp, p) { +#ifdef NO_INLINE + if ((dist = cdist01(p, r)) > 1) goto exit_if; +#else + {register int w,last;register unsigned int x;dist=0;if((last=cube.inword)!=-1) +{x=p[last]&r[last];if(x=~(x|x>>1)&cube.inmask)if((dist=count_ones(x))>1)goto +exit_if;for(w=1;w>1)&DISJOINT)if(dist==1||( +dist+=count_ones(x))>1)goto exit_if;}}}{register int w,var,last;register pcube +mask;for(var=cube.num_binary_vars;var1)goto exit_if;nextvar:;}} +#endif + if (dist == 0) { + fatal("ON-set and OFF-set are not orthogonal"); + } else { + (void) force_lower(xlower, p, r); + BB->active_count--; + RESET(p, ACTIVE); + } +exit_if: ; + } + + if (! setp_empty(xlower)) { + (void) set_diff(FREESET, FREESET, xlower);/* remove from free set */ + elim_lowering(BB, CC, RAISE, FREESET); + } + + if (debug & EXPAND1) + printf("ESSEN_PARTS:\tRAISE=%s FREESET=%s\n", pc1(RAISE), pc2(FREESET)); +} + +/* + essen_raising -- determine which parts may always be added to + the raising set without restricting further expansions + + General rule: if some part is not blocked by any cube of BB, then + this part can always be raised. +*/ + +void essen_raising(BB, RAISE, FREESET) +register pcover BB; +pcube RAISE, FREESET; +{ + register pcube last, p, xraise = cube.temp[0]; + + /* Form union of all cubes of BB, and then take complement wrt FREESET */ + (void) set_copy(xraise, cube.emptyset); + foreach_active_set(BB, last, p) + INLINEset_or(xraise, xraise, p); + (void) set_diff(xraise, FREESET, xraise); + + (void) set_or(RAISE, RAISE, xraise); /* add to raising set */ + (void) set_diff(FREESET, FREESET, xraise); /* remove from free set */ + + if (debug & EXPAND1) + printf("ESSEN_RAISING:\tRAISE=%s FREESET=%s\n", + pc1(RAISE), pc2(FREESET)); +} + +/* + elim_lowering -- after removing parts from FREESET, we can reduce the + size of both BB and CC. + + We mark as inactive any cube of BB which does not intersect the + overexpanded cube (i.e., RAISE + FREESET). Likewise, we remove + from CC any cube which is not covered by the overexpanded cube. +*/ + +void elim_lowering(BB, CC, RAISE, FREESET) +pcover BB, CC; +pcube RAISE, FREESET; +{ + register pcube p, r = set_or(cube.temp[0], RAISE, FREESET); + pcube last; + + /* + * Remove sets of BB which are orthogonal to future expansions + */ + foreach_active_set(BB, last, p) { +#ifdef NO_INLINE + if (! cdist0(p, r)) +#else + {register int w,lastw;register unsigned int x;if((lastw=cube.inword)!=-1){x=p[ +lastw]&r[lastw];if(~(x|x>>1)&cube.inmask)goto lfalse;for(w=1;w>1)&DISJOINT)goto lfalse;}}}{register int w,var,lastw;register +pcube mask;for(var=cube.num_binary_vars;varactive_count--, RESET(p, ACTIVE); + } + + + /* + * Remove sets of CC which cannot be covered by future expansions + */ + if (CC != (pcover) NULL) { + foreach_active_set(CC, last, p) { +#ifdef NO_INLINE + if (! setp_implies(p, r)) +#else + INLINEsetp_implies(p, r, /* when false => */ goto false1); + /* when true => go to end of loop */ continue; + false1: +#endif + CC->active_count--, RESET(p, ACTIVE); + } + } +} + +/* + most_frequent -- When all else fails, select a reasonable part to raise + The active cubes of CC are the cubes which are covered by the + overexpanded cube of the original cube (however, we know that none + of them can actually be covered by a feasible expansion of the + original cube). We resort to the MINI strategy of selecting to + raise the part which will cover the same part in the most cubes of CC. +*/ +int most_frequent(CC, FREESET) +pcover CC; +pcube FREESET; +{ + register int i, best_part, best_count, *count; + register pset p, last; + + /* Count occurences of each variable */ + count = ALLOC(int, cube.size); + for(i = 0; i < cube.size; i++) + count[i] = 0; + if (CC != (pcover) NULL) + foreach_active_set(CC, last, p) + set_adjcnt(p, count, 1); + + /* Now find which free part occurs most often */ + best_count = best_part = -1; + for(i = 0; i < cube.size; i++) + if (is_in_set(FREESET,i) && count[i] > best_count) { + best_part = i; + best_count = count[i]; + } + FREE(count); + + if (debug & EXPAND1) + printf("MOST_FREQUENT:\tbest=%d FREESET=%s\n", best_part, pc2(FREESET)); + return best_part; +} + +/* + setup_BB_CC -- set up the blocking and covering set families; + + Note that the blocking family is merely the set of cubes of R, and + that CC is the set of cubes of F which might possibly be covered + (i.e., nonprime cubes, and cubes not already covered) +*/ + +void setup_BB_CC(BB, CC) +register pcover BB, CC; +{ + register pcube p, last; + + /* Create the block and cover set families */ + BB->active_count = BB->count; + foreach_set(BB, last, p) + SET(p, ACTIVE); + + if (CC != (pcover) NULL) { + CC->active_count = CC->count; + foreach_set(CC, last, p) + if (TESTP(p, COVERED) || TESTP(p, PRIME)) + CC->active_count--, RESET(p, ACTIVE); + else + SET(p, ACTIVE); + } +} + +/* + select_feasible -- Determine if there are cubes which can be covered, + and if so, raise those parts necessary to cover as many as possible. + + We really don't check to maximize the number that can be covered; + instead, we check, for each fcc, how many other fcc remain fcc + after expanding to cover the fcc. (Essentially one-level lookahead). +*/ + +void select_feasible(BB, CC, RAISE, FREESET, SUPER_CUBE, num_covered) +pcover BB, CC; +pcube RAISE, FREESET, SUPER_CUBE; +int *num_covered; +{ + register pcube p, last, bestfeas, *feas; + register int i, j; + pcube *feas_new_lower; + int bestcount, bestsize, count, size, numfeas, lastfeas; + pcover new_lower; + + /* Start out with all cubes covered by the over-expanded cube as + * the "possibly" feasibly-covered cubes (pfcc) + */ + feas = ALLOC(pcube, CC->active_count); + numfeas = 0; + foreach_active_set(CC, last, p) + feas[numfeas++] = p; + + /* Setup extra cubes to record parts forced low after a covering */ + feas_new_lower = ALLOC(pcube, CC->active_count); + new_lower = new_cover(numfeas); + for(i = 0; i < numfeas; i++) + feas_new_lower[i] = GETSET(new_lower, i); + + +loop: + /* Find the essentially raised parts -- this might cover some cubes + for us, without having to find out if they are fcc or not + */ + essen_raising(BB, RAISE, FREESET); + + /* Now check all "possibly" feasibly covered cubes to check feasibility */ + lastfeas = numfeas; + numfeas = 0; + for(i = 0; i < lastfeas; i++) { + p = feas[i]; + + /* Check active because essen_parts might have removed it */ + if (TESTP(p, ACTIVE)) { + + /* See if the cube is already covered by RAISE -- + * this can happen because of essen_raising() or because of + * the previous "loop" + */ + if (setp_implies(p, RAISE)) { + (*num_covered) += 1; + (void) set_or(SUPER_CUBE, SUPER_CUBE, p); + CC->active_count--; + RESET(p, ACTIVE); + SET(p, COVERED); + /* otherwise, test if it is feasibly covered */ + } else if (feasibly_covered(BB,p,RAISE,feas_new_lower[numfeas])) { + feas[numfeas] = p; /* save the fcc */ + numfeas++; + } + } + } + if (debug & EXPAND1) + printf("SELECT_FEASIBLE: started with %d pfcc, ended with %d fcc\n", + lastfeas, numfeas); + + /* Exit here if there are no feasibly covered cubes */ + if (numfeas == 0) { + FREE(feas); + FREE(feas_new_lower); + free_cover(new_lower); + return; + } + + /* Now find which is the best feasibly covered cube */ + bestcount = 0; + bestsize = 9999; + for(i = 0; i < numfeas; i++) { + size = set_dist(feas[i], FREESET); /* # of newly raised parts */ + count = 0; /* # of other cubes which remain fcc after raising */ + +#define NEW +#ifdef NEW + for(j = 0; j < numfeas; j++) + if (setp_disjoint(feas_new_lower[i], feas[j])) + count++; +#else + for(j = 0; j < numfeas; j++) + if (setp_implies(feas[j], feas[i])) + count++; +#endif + if (count > bestcount) { + bestcount = count; + bestfeas = feas[i]; + bestsize = size; + } else if (count == bestcount && size < bestsize) { + bestfeas = feas[i]; + bestsize = size; + } + } + + /* Add the necessary parts to the raising set */ + (void) set_or(RAISE, RAISE, bestfeas); + (void) set_diff(FREESET, FREESET, RAISE); + if (debug & EXPAND1) + printf("FEASIBLE: \tRAISE=%s FREESET=%s\n", pc1(RAISE), pc2(FREESET)); + essen_parts(BB, CC, RAISE, FREESET); + goto loop; +/* NOTREACHED */ +} + +/* + feasibly_covered -- determine if the cube c is feasibly covered + (i.e., if it is possible to raise all of the necessary variables + while still insuring orthogonality with R). Also, if c is feasibly + covered, then compute the new set of parts which are forced into + the lowering set. +*/ + +bool feasibly_covered(BB, c, RAISE, new_lower) +pcover BB; +pcube c, RAISE, new_lower; +{ + register pcube p, r = set_or(cube.temp[0], RAISE, c); + int dist; + pcube lastp; + + set_copy(new_lower, cube.emptyset); + foreach_active_set(BB, lastp, p) { +#ifdef NO_INLINE + if ((dist = cdist01(p, r)) > 1) goto exit_if; +#else + {register int w,last;register unsigned int x;dist=0;if((last=cube.inword)!=-1) +{x=p[last]&r[last];if(x=~(x|x>>1)&cube.inmask)if((dist=count_ones(x))>1)goto +exit_if;for(w=1;w>1)&DISJOINT)if(dist==1||( +dist+=count_ones(x))>1)goto exit_if;}}}{register int w,var,last;register pcube +mask;for(var=cube.num_binary_vars;var1)goto exit_if;nextvar:;}} +#endif + if (dist == 0) + return FALSE; + else + (void) force_lower(new_lower, p, r); + exit_if: ; + } + return TRUE; +} + +/* + mincov -- transform the problem of expanding a cube to a maximally- + large prime implicant into the problem of selecting a minimum + cardinality cover over a family of sets. + + When we get to this point, we must unravel the remaining off-set. + This may be painful. +*/ + +void mincov(BB, RAISE, FREESET) +pcover BB; +pcube RAISE, FREESET; +{ + int expansion, nset, var, dist; + pset_family B; + register pcube xraise=cube.temp[0], xlower, p, last, plower; + +#ifdef RANDOM_MINCOV + dist = random() % set_ord(FREESET); + for(var = 0; var < cube.size && dist >= 0; var++) { + if (is_in_set(FREESET, var)) { + dist--; + } + } + + set_insert(RAISE, var); + set_remove(FREESET, var); + (void) essen_parts(BB, /*CC*/ (pcover) NULL, RAISE, FREESET); +#else + + /* Create B which are those cubes which we must avoid intersecting */ + B = new_cover(BB->active_count); + foreach_active_set(BB, last, p) { + plower = set_copy(GETSET(B, B->count++), cube.emptyset); + (void) force_lower(plower, p, RAISE); + } + + /* Determine how many sets it will blow up into after the unravel */ + nset = 0; + foreach_set(B, last, p) { + expansion = 1; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + if ((dist=set_dist(p, cube.var_mask[var])) > 1) { + expansion *= dist; + if (expansion > 500) goto heuristic_mincov; + } + } + nset += expansion; + if (nset > 500) goto heuristic_mincov; + } + + B = unravel(B, cube.num_binary_vars); + xlower = do_sm_minimum_cover(B); + + /* Add any remaining free parts to the raising set */ + (void) set_or(RAISE, RAISE, set_diff(xraise, FREESET, xlower)); + (void) set_copy(FREESET, cube.emptyset); /* free set is empty */ + BB->active_count = 0; /* BB satisfied */ + if (debug & EXPAND1) { + printf("MINCOV: \tRAISE=%s FREESET=%s\n", pc1(RAISE), pc2(FREESET)); + } + sf_free(B); + set_free(xlower); + return; + +heuristic_mincov: + sf_free(B); + /* most_frequent will pick first free part */ + set_insert(RAISE, most_frequent(/*CC*/ (pcover) NULL, FREESET)); + (void) set_diff(FREESET, FREESET, RAISE); + essen_parts(BB, /*CC*/ (pcover) NULL, RAISE, FREESET); + return; +#endif +} + +/* + find_all_primes -- find all of the primes which cover the + currently reduced BB +*/ +pcover find_all_primes(BB, RAISE, FREESET) +pcover BB; +register pcube RAISE, FREESET; +{ + register pset last, p, plower; + pset_family B, B1; + + if (BB->active_count == 0) { + B1 = new_cover(1); + p = GETSET(B1, B1->count++); + (void) set_copy(p, RAISE); + SET(p, PRIME); + } else { + B = new_cover(BB->active_count); + foreach_active_set(BB, last, p) { + plower = set_copy(GETSET(B, B->count++), cube.emptyset); + (void) force_lower(plower, p, RAISE); + } + B = sf_rev_contain(unravel(B, cube.num_binary_vars)); + B1 = exact_minimum_cover(B); + foreach_set(B1, last, p) { + INLINEset_diff(p, FREESET, p); + INLINEset_or(p, p, RAISE); + SET(p, PRIME); + } + free_cover(B); + } + return B1; +} + +/* + all_primes -- foreach cube in F, generate all of the primes + which cover the cube. +*/ + +pcover all_primes(F, R) +pcover F, R; +{ + register pcube last, p, RAISE, FREESET; + pcover Fall_primes, B1; + + FREESET = new_cube(); + RAISE = new_cube(); + Fall_primes = new_cover(F->count); + + foreach_set(F, last, p) { + if (TESTP(p, PRIME)) { + Fall_primes = sf_addset(Fall_primes, p); + } else { + /* Setup for call to essential parts */ + (void) set_copy(RAISE, p); + (void) set_diff(FREESET, cube.fullset, RAISE); + setup_BB_CC(R, /* CC */ (pcover) NULL); + essen_parts(R, /* CC */ (pcover) NULL, RAISE, FREESET); + + /* Find all of the primes, and add them to the prime set */ + B1 = find_all_primes(R, RAISE, FREESET); + Fall_primes = sf_append(Fall_primes, B1); + } + } + + set_free(RAISE); + set_free(FREESET); + return Fall_primes; +} diff --git a/benchmarks/benchmarks/espresso/gasp.c b/benchmarks/benchmarks/espresso/gasp.c new file mode 100644 index 0000000..b9a3d90 --- /dev/null +++ b/benchmarks/benchmarks/espresso/gasp.c @@ -0,0 +1,219 @@ +/* + module: gasp.c + + The "last_gasp" heuristic computes the reduction of each cube in + the cover (without replacement) and then performs an expansion of + these cubes. The cubes which expand to cover some other cube are + added to the original cover and irredundant finds a minimal subset. + + If one of the reduced cubes expands to cover some other reduced + cube, then the new prime thus generated is a candidate for reducing + the size of the cover. + + super_gasp is a variation on this strategy which extracts a minimal + subset from the set of all prime implicants which cover all + maximally reduced cubes. +*/ + +#include "espresso.h" + + +/* + * reduce_gasp -- compute the maximal reduction of each cube of F + * + * If a cube does not reduce, it remains prime; otherwise, it is marked + * as nonprime. If the cube is redundant (should NEVER happen here) we + * just crap out ... + * + * A cover with all of the cubes of F is returned. Those that did + * reduce are marked "NONPRIME"; those that reduced are marked "PRIME". + * The cubes are in the same order as in F. + */ +static pcover reduce_gasp(F, D) +pcover F, D; +{ + pcube p, last, cunder, *FD; + pcover G; + + G = new_cover(F->count); + FD = cube2list(F, D); + + /* Reduce cubes of F without replacement */ + foreach_set(F, last, p) { + cunder = reduce_cube(FD, p); + if (setp_empty(cunder)) { + fatal("empty reduction in reduce_gasp, shouldn't happen"); + } else if (setp_equal(cunder, p)) { + SET(cunder, PRIME); /* just to make sure */ + G = sf_addset(G, p); /* it did not reduce ... */ + } else { + RESET(cunder, PRIME); /* it reduced ... */ + G = sf_addset(G, cunder); + } + if (debug & GASP) { + printf("REDUCE_GASP: %s reduced to %s\n", pc1(p), pc2(cunder)); + } + free_cube(cunder); + } + + free_cubelist(FD); + return G; +} + +/* + * expand_gasp -- expand each nonprime cube of F into a prime implicant + * + * The gasp strategy differs in that only those cubes which expand to + * cover some other cube are saved; also, all cubes are expanded + * regardless of whether they become covered or not. + */ + +pcover expand_gasp(F, D, R, Foriginal) +INOUT pcover F; +IN pcover D; +IN pcover R; +IN pcover Foriginal; +{ + int c1index; + pcover G; + + /* Try to expand each nonprime and noncovered cube */ + G = new_cover(10); + for(c1index = 0; c1index < F->count; c1index++) { + expand1_gasp(F, D, R, Foriginal, c1index, &G); + } + G = sf_dupl(G); + G = expand(G, R, /*nonsparse*/ FALSE); /* Make them prime ! */ + return G; +} + + + +/* + * expand1 -- Expand a single cube against the OFF-set, using the gasp strategy + */ +void expand1_gasp(F, D, R, Foriginal, c1index, G) +pcover F; /* reduced cubes of ON-set */ +pcover D; /* DC-set */ +pcover R; /* OFF-set */ +pcover Foriginal; /* ON-set before reduction (same order as F) */ +int c1index; /* which index of F (or Freduced) to be checked */ +pcover *G; +{ + register int c2index; + register pcube p, last, c2under; + pcube RAISE, FREESET, temp, *FD, c2essential; + pcover F1; + + if (debug & EXPAND1) { + printf("\nEXPAND1_GASP: \t%s\n", pc1(GETSET(F, c1index))); + } + + RAISE = new_cube(); + FREESET = new_cube(); + temp = new_cube(); + + /* Initialize the OFF-set */ + R->active_count = R->count; + foreach_set(R, last, p) { + SET(p, ACTIVE); + } + /* Initialize the reduced ON-set, all nonprime cubes become active */ + F->active_count = F->count; + foreachi_set(F, c2index, c2under) { + if (c1index == c2index || TESTP(c2under, PRIME)) { + F->active_count--; + RESET(c2under, ACTIVE); + } else { + SET(c2under, ACTIVE); + } + } + + /* Initialize the raising and unassigned sets */ + (void) set_copy(RAISE, GETSET(F, c1index)); + (void) set_diff(FREESET, cube.fullset, RAISE); + + /* Determine parts which must be lowered */ + essen_parts(R, F, RAISE, FREESET); + + /* Determine parts which can always be raised */ + essen_raising(R, RAISE, FREESET); + + /* See which, if any, of the reduced cubes we can cover */ + foreachi_set(F, c2index, c2under) { + if (TESTP(c2under, ACTIVE)) { + /* See if this cube can be covered by an expansion */ + if (setp_implies(c2under, RAISE) || + feasibly_covered(R, c2under, RAISE, temp)) { + + /* See if c1under can expanded to cover c2 reduced against + * (F - c1) u c1under; if so, c2 can definitely be removed ! + */ + + /* Copy F and replace c1 with c1under */ + F1 = sf_save(Foriginal); + (void) set_copy(GETSET(F1, c1index), GETSET(F, c1index)); + + /* Reduce c2 against ((F - c1) u c1under) */ + FD = cube2list(F1, D); + c2essential = reduce_cube(FD, GETSET(F1, c2index)); + free_cubelist(FD); + sf_free(F1); + + /* See if c2essential is covered by an expansion of c1under */ + if (feasibly_covered(R, c2essential, RAISE, temp)) { + (void) set_or(temp, RAISE, c2essential); + RESET(temp, PRIME); /* cube not prime */ + *G = sf_addset(*G, temp); + } + set_free(c2essential); + } + } + } + + free_cube(RAISE); + free_cube(FREESET); + free_cube(temp); +} + +/* irred_gasp -- Add new primes to F and find an irredundant subset */ +pcover irred_gasp(F, D, G) +pcover F, D, G; /* G is disposed of */ +{ + if (G->count != 0) + F = irredundant(sf_append(F, G), D); + else + free_cover(G); + return F; +} + + +/* last_gasp */ +pcover last_gasp(F, D, R, cost) +pcover F, D, R; +cost_t *cost; +{ + pcover G, G1; + + EXECUTE(G = reduce_gasp(F, D), GREDUCE_TIME, G, *cost); + EXECUTE(G1 = expand_gasp(G, D, R, F), GEXPAND_TIME, G1, *cost); + free_cover(G); + EXECUTE(F = irred_gasp(F, D, G1), GIRRED_TIME, F, *cost); + return F; +} + + +/* super_gasp */ +pcover super_gasp(F, D, R, cost) +pcover F, D, R; +cost_t *cost; +{ + pcover G, G1; + + EXECUTE(G = reduce_gasp(F, D), GREDUCE_TIME, G, *cost); + EXECUTE(G1 = all_primes(G, R), GEXPAND_TIME, G1, *cost); + free_cover(G); + EXEC(G = sf_dupl(sf_append(F, G1)), "NEWPRIMES", G); + EXECUTE(F = irredundant(G, D), IRRED_TIME, F, *cost); + return F; +} diff --git a/benchmarks/benchmarks/espresso/getopt.c b/benchmarks/benchmarks/espresso/getopt.c new file mode 100644 index 0000000..017c907 --- /dev/null +++ b/benchmarks/benchmarks/espresso/getopt.c @@ -0,0 +1,45 @@ +#include "espresso.h" +#include "port.h" +/* File : getopt.c + Author : Henry Spencer, University of Toronto + Updated: 28 April 1984 + Purpose: get option letter from argv. +*/ +#define NullS ((char *) 0) + +char *optarg; /* Global argument pointer. */ +int optind = 0; /* Global argv index. */ + +int getopt(int argc, char * const * argv, const char * optstring) + { + register int c; + register char *place; + static char *scan = NullS; /* Private scan pointer. */ + + optarg = NullS; + + if (scan == NullS || *scan == '\0') { + if (optind == 0) optind++; + if (optind >= argc) return EOF; + place = argv[optind]; + if (place[0] != '-' || place[1] == '\0') return EOF; + optind++; + if (place[1] == '-' && place[2] == '\0') return EOF; + scan = place+1; + } + + c = *scan++; + place = strchr(optstring, c); + if (place == NullS || c == ':') { + fprintf(stderr, "%s: unknown option %c\n", argv[0], c); + return '?'; + } + if (*++place == ':') { + if (*scan != '\0') { + optarg = scan, scan = NullS; + } else { + optarg = argv[optind], optind++; + } + } + return c; + } diff --git a/benchmarks/benchmarks/espresso/gimpel.c b/benchmarks/benchmarks/espresso/gimpel.c new file mode 100644 index 0000000..d1122b7 --- /dev/null +++ b/benchmarks/benchmarks/espresso/gimpel.c @@ -0,0 +1,98 @@ +#include "espresso.h" +#include "mincov_int.h" + + +/* + * check for: + * + * c1 c2 rest + * -- -- --- + * 1 1 0 0 0 0 <-- primary row + * 1 0 S1 <-- secondary row + * 0 1 T1 + * 0 1 T2 + * 0 1 Tn + * 0 0 R + */ + +int +gimpel_reduce(A, select, weight, lb, bound, depth, stats, best) +sm_matrix *A; +solution_t *select; +int *weight; +int lb; +int bound; +int depth; +stats_t *stats; +solution_t **best; +{ + register sm_row *prow, *save_sec; + register sm_col *c1, *c2; + register sm_element *p, *p1; + int c1_col_num, c2_col_num, primary_row_num, secondary_row_num; + int reduce_it; + + reduce_it = 0; + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + if (prow->length == 2) { + c1 = sm_get_col(A, prow->first_col->col_num); + c2 = sm_get_col(A, prow->last_col->col_num); + if (c1->length == 2) { + reduce_it = 1; + } else if (c2->length == 2) { + c1 = sm_get_col(A, prow->last_col->col_num); + c2 = sm_get_col(A, prow->first_col->col_num); + reduce_it = 1; + } + if (reduce_it) { + primary_row_num = prow->row_num; + secondary_row_num = c1->first_row->row_num; + if (secondary_row_num == primary_row_num) { + secondary_row_num = c1->last_row->row_num; + } + break; + } + } + } + + if (reduce_it) { + c1_col_num = c1->col_num; + c2_col_num = c2->col_num; + save_sec = sm_row_dup(sm_get_row(A, secondary_row_num)); + sm_row_remove(save_sec, c1_col_num); + + for(p = c2->first_row; p != 0; p = p->next_row) { + if (p->row_num != primary_row_num) { + /* merge rows S1 and T */ + for(p1 = save_sec->first_col; p1 != 0; p1 = p1->next_col) { + (void) sm_insert(A, p->row_num, p1->col_num); + } + } + } + + sm_delcol(A, c1_col_num); + sm_delcol(A, c2_col_num); + sm_delrow(A, primary_row_num); + sm_delrow(A, secondary_row_num); + + stats->gimpel_count++; + stats->gimpel++; + *best = sm_mincov(A, select, weight, lb-1, bound-1, depth, stats); + stats->gimpel--; + + if (*best != NIL(solution_t)) { + /* is secondary row covered ? */ + if (sm_row_intersects(save_sec, (*best)->row)) { + /* yes, actually select c2 */ + solution_add(*best, weight, c2_col_num); + } else { + solution_add(*best, weight, c1_col_num); + } + } + + sm_row_free(save_sec); + return 1; + } else { + return 0; + } +} diff --git a/benchmarks/benchmarks/espresso/globals.c b/benchmarks/benchmarks/espresso/globals.c new file mode 100644 index 0000000..dc0b958 --- /dev/null +++ b/benchmarks/benchmarks/espresso/globals.c @@ -0,0 +1,67 @@ +#include "espresso.h" + +/* + * Global Variable Declarations + */ + +unsigned int debug; /* debug parameter */ +bool verbose_debug; /* -v: whether to print a lot */ +char *total_name[TIME_COUNT]; /* basic function names */ +long total_time[TIME_COUNT]; /* time spent in basic fcts */ +int total_calls[TIME_COUNT]; /* # calls to each fct */ + +bool echo_comments; /* turned off by -eat option */ +bool echo_unknown_commands; /* always true ?? */ +bool force_irredundant; /* -nirr command line option */ +bool skip_make_sparse; +bool kiss; /* -kiss command line option */ +bool pos; /* -pos command line option */ +bool print_solution; /* -x command line option */ +bool recompute_onset; /* -onset command line option */ +bool remove_essential; /* -ness command line option */ +bool single_expand; /* -fast command line option */ +bool summary; /* -s command line option */ +bool trace; /* -t command line option */ +bool unwrap_onset; /* -nunwrap command line option */ +bool use_random_order; /* -random command line option */ +bool use_super_gasp; /* -strong command line option */ +char *filename; /* filename PLA was read from */ + +struct pla_types_struct pla_types[] = { + "-f", F_type, + "-r", R_type, + "-d", D_type, + "-fd", FD_type, + "-fr", FR_type, + "-dr", DR_type, + "-fdr", FDR_type, + "-fc", F_type | CONSTRAINTS_type, + "-rc", R_type | CONSTRAINTS_type, + "-dc", D_type | CONSTRAINTS_type, + "-fdc", FD_type | CONSTRAINTS_type, + "-frc", FR_type | CONSTRAINTS_type, + "-drc", DR_type | CONSTRAINTS_type, + "-fdrc", FDR_type | CONSTRAINTS_type, + "-pleasure", PLEASURE_type, + "-eqn", EQNTOTT_type, + "-eqntott", EQNTOTT_type, + "-kiss", KISS_type, + "-cons", CONSTRAINTS_type, + "-scons", SYMBOLIC_CONSTRAINTS_type, + 0, 0 +}; + + +struct cube_struct cube, temp_cube_save; +struct cdata_struct cdata, temp_cdata_save; + +int bit_count[256] = { + 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, + 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 +}; diff --git a/benchmarks/benchmarks/espresso/hack.c b/benchmarks/benchmarks/espresso/hack.c new file mode 100644 index 0000000..6cb76c0 --- /dev/null +++ b/benchmarks/benchmarks/espresso/hack.c @@ -0,0 +1,632 @@ +#include "espresso.h" + +map_dcset(PLA) +pPLA PLA; +{ + int var, i; + pcover Tplus, Tminus, Tplusbar, Tminusbar; + pcover newf, term1, term2, dcset, dcsetbar; + pcube cplus, cminus, last, p; + + if (PLA->label == NIL(char *) || PLA->label[0] == NIL(char)) + return NULL; + + /* try to find a binary variable named "DONT_CARE" */ + var = -1; + for(i = 0; i < cube.num_binary_vars * 2; i++) { + if (strncmp(PLA->label[i], "DONT_CARE", 9) == 0 || + strncmp(PLA->label[i], "DONTCARE", 8) == 0 || + strncmp(PLA->label[i], "dont_care", 9) == 0 || + strncmp(PLA->label[i], "dontcare", 8) == 0) { + var = i/2; + break; + } + } + if (var == -1) { + return NULL; + } + + /* form the cofactor cubes for the don't-care variable */ + cplus = set_save(cube.fullset); + cminus = set_save(cube.fullset); + set_remove(cplus, var*2); + set_remove(cminus, var*2 + 1); + + /* form the don't-care set */ + EXEC(simp_comp(cofactor(cube1list(PLA->F), cplus), &Tplus, &Tplusbar), + "simpcomp+", Tplus); + EXEC(simp_comp(cofactor(cube1list(PLA->F), cminus), &Tminus, &Tminusbar), + "simpcomp-", Tminus); + EXEC(term1 = cv_intersect(Tplus, Tminusbar), "term1 ", term1); + EXEC(term2 = cv_intersect(Tminus, Tplusbar), "term2 ", term2); + EXEC(dcset = sf_union(term1, term2), "union ", dcset); + EXEC(simp_comp(cube1list(dcset), &PLA->D, &dcsetbar), "simplify", PLA->D); + EXEC(newf = cv_intersect(PLA->F, dcsetbar), "separate ", PLA->F); + free_cover(PLA->F); + PLA->F = newf; + free_cover(Tplus); + free_cover(Tminus); + free_cover(Tplusbar); + free_cover(Tminusbar); + free_cover(dcsetbar); + + /* remove any cubes dependent on the DONT_CARE variable */ + (void) sf_active(PLA->F); + foreach_set(PLA->F, last, p) { + if (! is_in_set(p, var*2) || ! is_in_set(p, var*2+1)) { + RESET(p, ACTIVE); + } + } + PLA->F = sf_inactive(PLA->F); + + /* resize the cube and delete the don't-care variable */ + setdown_cube(); + for(i = 2*var+2; i < cube.size; i++) { + PLA->label[i-2] = PLA->label[i]; + } + for(i = var+1; i < cube.num_vars; i++) { + cube.part_size[i-1] = cube.part_size[i]; + } + cube.num_binary_vars--; + cube.num_vars--; + cube_setup(); + PLA->F = sf_delc(PLA->F, 2*var, 2*var+1); + PLA->D = sf_delc(PLA->D, 2*var, 2*var+1); +} + +map_output_symbolic(PLA) +pPLA PLA; +{ + pset_family newF, newD; + pset compress; + symbolic_t *p1; + symbolic_list_t *p2; + int i, bit, tot_size, base, old_size; + + /* Remove the DC-set from the ON-set (is this necessary ??) */ + if (PLA->D->count > 0) { + sf_free(PLA->F); + PLA->F = complement(cube2list(PLA->D, PLA->R)); + } + + /* tot_size = width added for all symbolic variables */ + tot_size = 0; + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + if (p2->pos<0 || p2->pos>=cube.part_size[cube.output]) { + fatal("symbolic-output index out of range"); +/* } else if (p2->variable != cube.output) { + fatal("symbolic-output label must be an output");*/ + } + } + tot_size += 1 << p1->symbolic_list_length; + } + + /* adjust the indices to skip over new outputs */ + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + p2->pos += tot_size; + } + } + + /* resize the cube structure -- add enough for the one-hot outputs */ + old_size = cube.size; + cube.part_size[cube.output] += tot_size; + setdown_cube(); + cube_setup(); + + /* insert space in the output part for the one-hot output */ + base = cube.first_part[cube.output]; + PLA->F = sf_addcol(PLA->F, base, tot_size); + PLA->D = sf_addcol(PLA->D, base, tot_size); + PLA->R = sf_addcol(PLA->R, base, tot_size); + + /* do the real work */ + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + newF = new_cover(100); + newD = new_cover(100); + find_inputs(NIL(set_family_t), PLA, p1->symbolic_list, base, 0, + &newF, &newD); +/* + * Not sure what this means + find_dc_inputs(PLA, p1->symbolic_list, + base, 1 << p1->symbolic_list_length, &newF, &newD); + */ + free_cover(PLA->F); + PLA->F = newF; +/* + * retain OLD DC-set -- but we've lost the don't-care arc information + * (it defaults to branch to the zero state) + free_cover(PLA->D); + PLA->D = newD; + */ + free_cover(newD); + base += 1 << p1->symbolic_list_length; + } + + /* delete the old outputs, and resize the cube */ + compress = set_full(newF->sf_size); + for(p1=PLA->symbolic_output; p1!=NIL(symbolic_t); p1=p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + bit = cube.first_part[cube.output] + p2->pos; + set_remove(compress, bit); + } + } + cube.part_size[cube.output] -= newF->sf_size - set_ord(compress); + setdown_cube(); + cube_setup(); + PLA->F = sf_compress(PLA->F, compress); + PLA->D = sf_compress(PLA->D, compress); + if (cube.size != PLA->F->sf_size) fatal("error"); + + /* Quick minimization */ + PLA->F = sf_contain(PLA->F); + PLA->D = sf_contain(PLA->D); + for(i = 0; i < cube.num_vars; i++) { + PLA->F = d1merge(PLA->F, i); + PLA->D = d1merge(PLA->D, i); + } + PLA->F = sf_contain(PLA->F); + PLA->D = sf_contain(PLA->D); + + free_cover(PLA->R); + PLA->R = new_cover(0); + + symbolic_hack_labels(PLA, PLA->symbolic_output, + compress, cube.size, old_size, tot_size); + set_free(compress); +} + + +find_inputs(A, PLA, list, base, value, newF, newD) +pcover A; +pPLA PLA; +symbolic_list_t *list; +int base, value; +pcover *newF, *newD; +{ + pcover S, S1; + register pset last, p; + + /* + * A represents th 'input' values for which the outputs assume + * the integer value 'value + */ + if (list == NIL(symbolic_list_t)) { + /* + * Simulate these inputs against the on-set; then, insert into the + * new on-set a 1 in the proper position + */ + S = cv_intersect(A, PLA->F); + foreach_set(S, last, p) { + set_insert(p, base + value); + } + *newF = sf_append(*newF, S); + + /* + * 'simulate' these inputs against the don't-care set + S = cv_intersect(A, PLA->D); + *newD = sf_append(*newD, S); + */ + + } else { + /* intersect and recur with the OFF-set */ + S = cof_output(PLA->R, cube.first_part[cube.output] + list->pos); + if (A != NIL(set_family_t)) { + S1 = cv_intersect(A, S); + free_cover(S); + S = S1; + } + find_inputs(S, PLA, list->next, base, value*2, newF, newD); + free_cover(S); + + /* intersect and recur with the ON-set */ + S = cof_output(PLA->F, cube.first_part[cube.output] + list->pos); + if (A != NIL(set_family_t)) { + S1 = cv_intersect(A, S); + free_cover(S); + S = S1; + } + find_inputs(S, PLA, list->next, base, value*2 + 1, newF, newD); + free_cover(S); + } +} + + +#if 0 +find_dc_inputs(PLA, list, base, maxval, newF, newD) +pPLA PLA; +symbolic_list_t *list; +int base, maxval; +pcover *newF, *newD; +{ + pcover A, S, S1; + symbolic_list_t *p2; + register pset p, last; + register int i; + + /* painfully find the points for which the symbolic output is dc */ + A = NIL(set_family_t); + for(p2=list; p2!=NIL(symbolic_list_t); p2=p2->next) { + S = cof_output(PLA->D, cube.first_part[cube.output] + p2->pos); + if (A == NIL(set_family_t)) { + A = S; + } else { + S1 = cv_intersect(A, S); + free_cover(S); + free_cover(A); + A = S1; + } + } + + S = cv_intersect(A, PLA->F); + *newF = sf_append(*newF, S); + + S = cv_intersect(A, PLA->D); + foreach_set(S, last, p) { + for(i = base; i < base + maxval; i++) { + set_insert(p, i); + } + } + *newD = sf_append(*newD, S); + free_cover(A); +} +#endif + +map_symbolic(PLA) +pPLA PLA; +{ + symbolic_t *p1; + symbolic_list_t *p2; + int var, base, num_vars, num_binary_vars, *new_part_size; + int new_size, size_added, num_deleted_vars, num_added_vars, newvar; + pset compress; + + /* Verify legal values are in the symbolic lists */ + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + if (p2->variable < 0 || p2->variable >= cube.num_binary_vars) { + fatal(".symbolic requires binary variables"); + } + } + } + + /* + * size_added = width added for all symbolic variables + * num_deleted_vars = # binary variables to be deleted + * num_added_vars = # new mv variables + * compress = a cube which will be used to compress the set families + */ + size_added = 0; + num_added_vars = 0; + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + size_added += 1 << p1->symbolic_list_length; + num_added_vars++; + } + compress = set_full(PLA->F->sf_size + size_added); + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) { + set_remove(compress, p2->variable*2); + set_remove(compress, p2->variable*2+1); + } + } + num_deleted_vars = ((PLA->F->sf_size + size_added) - set_ord(compress))/2; + + /* compute the new cube constants */ + num_vars = cube.num_vars - num_deleted_vars + num_added_vars; + num_binary_vars = cube.num_binary_vars - num_deleted_vars; + new_size = cube.size - num_deleted_vars*2 + size_added; + new_part_size = ALLOC(int, num_vars); + new_part_size[num_vars-1] = cube.part_size[cube.num_vars-1]; + for(var = cube.num_binary_vars; var < cube.num_vars-1; var++) { + new_part_size[var-num_deleted_vars] = cube.part_size[var]; + } + + /* re-size the covers, opening room for the new mv variables */ + base = cube.first_part[cube.output]; + PLA->F = sf_addcol(PLA->F, base, size_added); + PLA->D = sf_addcol(PLA->D, base, size_added); + PLA->R = sf_addcol(PLA->R, base, size_added); + + /* compute the values for the new mv variables */ + newvar = (cube.num_vars - 1) - num_deleted_vars; + for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) { + PLA->F = map_symbolic_cover(PLA->F, p1->symbolic_list, base); + PLA->D = map_symbolic_cover(PLA->D, p1->symbolic_list, base); + PLA->R = map_symbolic_cover(PLA->R, p1->symbolic_list, base); + base += 1 << p1->symbolic_list_length; + new_part_size[newvar++] = 1 << p1->symbolic_list_length; + } + + /* delete the binary variables which disappear */ + PLA->F = sf_compress(PLA->F, compress); + PLA->D = sf_compress(PLA->D, compress); + PLA->R = sf_compress(PLA->R, compress); + + symbolic_hack_labels(PLA, PLA->symbolic, compress, + new_size, cube.size, size_added); + setdown_cube(); + FREE(cube.part_size); + cube.num_vars = num_vars; + cube.num_binary_vars = num_binary_vars; + cube.part_size = new_part_size; + cube_setup(); + set_free(compress); +} + + +pcover map_symbolic_cover(T, list, base) +pcover T; +symbolic_list_t *list; +int base; +{ + pset last, p; + foreach_set(T, last, p) { + form_bitvector(p, base, 0, list); + } + return T; +} + + +form_bitvector(p, base, value, list) +pset p; /* old cube, looking at binary variables */ +int base; /* where in mv cube the new variable starts */ +int value; /* current value for this recursion */ +symbolic_list_t *list; /* current place in the symbolic list */ +{ + if (list == NIL(symbolic_list_t)) { + set_insert(p, base + value); + } else { + switch(GETINPUT(p, list->variable)) { + case ZERO: + form_bitvector(p, base, value*2, list->next); + break; + case ONE: + form_bitvector(p, base, value*2+1, list->next); + break; + case TWO: + form_bitvector(p, base, value*2, list->next); + form_bitvector(p, base, value*2+1, list->next); + break; + default: + fatal("bad cube in form_bitvector"); + } + } +} + + +symbolic_hack_labels(PLA, list, compress, new_size, old_size, size_added) +pPLA PLA; +symbolic_t *list; +pset compress; +int new_size, old_size, size_added; +{ + int i, base; + char **oldlabel; + symbolic_t *p1; + symbolic_label_t *p3; + + /* hack with the labels */ + if ((oldlabel = PLA->label) == NIL(char *)) + return 0; + PLA->label = ALLOC(char *, new_size); + for(i = 0; i < new_size; i++) { + PLA->label[i] = NIL(char); + } + + /* copy the binary variable labels and unchanged mv variable labels */ + base = 0; + for(i = 0; i < cube.first_part[cube.output]; i++) { + if (is_in_set(compress, i)) { + PLA->label[base++] = oldlabel[i]; + } else { + if (oldlabel[i] != NIL(char)) { + FREE(oldlabel[i]); + } + } + } + + /* add the user-defined labels for the symbolic outputs */ + for(p1 = list; p1 != NIL(symbolic_t); p1 = p1->next) { + p3 = p1->symbolic_label; + for(i = 0; i < (1 << p1->symbolic_list_length); i++) { + if (p3 == NIL(symbolic_label_t)) { + PLA->label[base+i] = ALLOC(char, 10); + (void) sprintf(PLA->label[base+i], "X%d", i); + } else { + PLA->label[base+i] = p3->label; + p3 = p3->next; + } + } + base += 1 << p1->symbolic_list_length; + } + + /* copy the labels for the binary outputs which remain */ + for(i = cube.first_part[cube.output]; i < old_size; i++) { + if (is_in_set(compress, i + size_added)) { + PLA->label[base++] = oldlabel[i]; + } else { + if (oldlabel[i] != NIL(char)) { + FREE(oldlabel[i]); + } + } + } + FREE(oldlabel); +} + +static pcover fsm_simplify(F) +pcover F; +{ + pcover D, R; + D = new_cover(0); + R = complement(cube1list(F)); + F = espresso(F, D, R); + free_cover(D); + free_cover(R); + return F; +} + + +disassemble_fsm(PLA, verbose_mode) +pPLA PLA; +int verbose_mode; +{ + int nin, nstates, nout; + int before, after, present_state, next_state, i, j; + pcube next_state_mask, present_state_mask, state_mask, p, p1, last; + pcover go_nowhere, F, tF; + + /* We make the DISGUSTING assumption that the first 'n' outputs have + * been created by .symbolic-output, and represent a one-hot encoding + * of the next state. 'n' is the size of the second-to-last multiple- + * valued variable (i.e., before the outputs + */ + + if (cube.num_vars - cube.num_binary_vars != 2) { + fprintf(stderr, + "use .symbolic and .symbolic-output to specify\n"); + fprintf(stderr, + "the present state and next state field information\n"); + fatal("disassemble_pla: need two multiple-valued variables\n"); + } + + nin = cube.num_binary_vars; + nstates = cube.part_size[cube.num_binary_vars]; + nout = cube.part_size[cube.num_vars - 1]; + if (nout < nstates) { + fprintf(stderr, + "use .symbolic and .symbolic-output to specify\n"); + fprintf(stderr, + "the present state and next state field information\n"); + fatal("disassemble_pla: # outputs < # states\n"); + } + + + present_state = cube.first_part[cube.num_binary_vars]; + present_state_mask = new_cube(); + for(i = 0; i < nstates; i++) { + set_insert(present_state_mask, i + present_state); + } + + next_state = cube.first_part[cube.num_binary_vars+1]; + next_state_mask = new_cube(); + for(i = 0; i < nstates; i++) { + set_insert(next_state_mask, i + next_state); + } + + state_mask = set_or(new_cube(), next_state_mask, present_state_mask); + + F = new_cover(10); + + + /* + * check for arcs which go from ANY state to state #i + */ + for(i = 0; i < nstates; i++) { + tF = new_cover(10); + foreach_set(PLA->F, last, p) { + if (setp_implies(present_state_mask, p)) { /* from any state ! */ + if (is_in_set(p, next_state + i)) { + tF = sf_addset(tF, p); + } + } + } + before = tF->count; + if (before > 0) { + tF = fsm_simplify(tF); + /* don't allow the next state to disappear ... */ + foreach_set(tF, last, p) { + set_insert(p, next_state + i); + } + after = tF->count; + F = sf_append(F, tF); + if (verbose_mode) { + printf("# state EVERY to %d, before=%d after=%d\n", + i, before, after); + } + } + } + + + /* + * some 'arcs' may NOT have a next state -- handle these + * we must unravel the present state part + */ + go_nowhere = new_cover(10); + foreach_set(PLA->F, last, p) { + if (setp_disjoint(p, next_state_mask)) { /* no next state !! */ + go_nowhere = sf_addset(go_nowhere, p); + } + } + before = go_nowhere->count; + go_nowhere = unravel_range(go_nowhere, + cube.num_binary_vars, cube.num_binary_vars); + after = go_nowhere->count; + F = sf_append(F, go_nowhere); + if (verbose_mode) { + printf("# state ANY to NOWHERE, before=%d after=%d\n", before, after); + } + + + /* + * minimize cover for all arcs from state #i to state #j + */ + for(i = 0; i < nstates; i++) { + for(j = 0; j < nstates; j++) { + tF = new_cover(10); + foreach_set(PLA->F, last, p) { + /* not EVERY state */ + if (! setp_implies(present_state_mask, p)) { + if (is_in_set(p, present_state + i)) { + if (is_in_set(p, next_state + j)) { + p1 = set_save(p); + set_diff(p1, p1, state_mask); + set_insert(p1, present_state + i); + set_insert(p1, next_state + j); + tF = sf_addset(tF, p1); + set_free(p1); + } + } + } + } + before = tF->count; + if (before > 0) { + tF = fsm_simplify(tF); + /* don't allow the next state to disappear ... */ + foreach_set(tF, last, p) { + set_insert(p, next_state + j); + } + after = tF->count; + F = sf_append(F, tF); + if (verbose_mode) { + printf("# state %d to %d, before=%d after=%d\n", + i, j, before, after); + } + } + } + } + + + free_cube(state_mask); + free_cube(present_state_mask); + free_cube(next_state_mask); + + free_cover(PLA->F); + PLA->F = F; + free_cover(PLA->D); + PLA->D = new_cover(0); + + setdown_cube(); + FREE(cube.part_size); + cube.num_binary_vars = nin; + cube.num_vars = nin + 3; + cube.part_size = ALLOC(int, cube.num_vars); + cube.part_size[cube.num_binary_vars] = nstates; + cube.part_size[cube.num_binary_vars+1] = nstates; + cube.part_size[cube.num_binary_vars+2] = nout - nstates; + cube_setup(); + + foreach_set(PLA->F, last, p) { + kiss_print_cube(stdout, PLA, p, "~1"); + } +} diff --git a/benchmarks/benchmarks/espresso/indep.c b/benchmarks/benchmarks/espresso/indep.c new file mode 100644 index 0000000..c462988 --- /dev/null +++ b/benchmarks/benchmarks/espresso/indep.c @@ -0,0 +1,126 @@ +#include "espresso.h" +#include "mincov_int.h" + +static sm_matrix *build_intersection_matrix(); + + +#if 0 +/* + * verify that all rows in 'indep' are actually independent ! + */ +static int +verify_indep_set(A, indep) +sm_matrix *A; +sm_row *indep; +{ + register sm_row *prow, *prow1; + register sm_element *p, *p1; + + for(p = indep->first_col; p != 0; p = p->next_col) { + prow = sm_get_row(A, p->col_num); + for(p1 = p->next_col; p1 != 0; p1 = p1->next_col) { + prow1 = sm_get_row(A, p1->col_num); + if (sm_row_intersects(prow, prow1)) { + return 0; + } + } + } + return 1; +} +#endif + +solution_t * +sm_maximal_independent_set(A, weight) +sm_matrix *A; +int *weight; +{ + register sm_row *best_row, *prow; + register sm_element *p; + int least_weight; + sm_row *save; + sm_matrix *B; + solution_t *indep; + + indep = solution_alloc(); + B = build_intersection_matrix(A); + + while (B->nrows > 0) { + /* Find the row which is disjoint from a maximum number of rows */ + best_row = B->first_row; + for(prow = B->first_row->next_row; prow != 0; prow = prow->next_row) { + if (prow->length < best_row->length) { + best_row = prow; + } + } + + /* Find which element in this row has least weight */ + if (weight == NIL(int)) { + least_weight = 1; + } else { + prow = sm_get_row(A, best_row->row_num); + least_weight = weight[prow->first_col->col_num]; + for(p = prow->first_col->next_col; p != 0; p = p->next_col) { + if (weight[p->col_num] < least_weight) { + least_weight = weight[p->col_num]; + } + } + } + indep->cost += least_weight; + (void) sm_row_insert(indep->row, best_row->row_num); + + /* Discard the rows which intersect this row */ + save = sm_row_dup(best_row); + for(p = save->first_col; p != 0; p = p->next_col) { + sm_delrow(B, p->col_num); + sm_delcol(B, p->col_num); + } + sm_row_free(save); + } + + sm_free(B); + +/* + if (! verify_indep_set(A, indep->row)) { + fail("sm_maximal_independent_set: row set is not independent"); + } +*/ + return indep; +} + +static sm_matrix * +build_intersection_matrix(A) +sm_matrix *A; +{ + register sm_row *prow, *prow1; + register sm_element *p, *p1; + register sm_col *pcol; + sm_matrix *B; + + /* Build row-intersection matrix */ + B = sm_alloc(); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + + /* Clear flags on all rows we can reach from row 'prow' */ + for(p = prow->first_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + for(p1 = pcol->first_row; p1 != 0; p1 = p1->next_row) { + prow1 = sm_get_row(A, p1->row_num); + prow1->flag = 0; + } + } + + /* Now record which rows can be reached */ + for(p = prow->first_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + for(p1 = pcol->first_row; p1 != 0; p1 = p1->next_row) { + prow1 = sm_get_row(A, p1->row_num); + if (! prow1->flag) { + prow1->flag = 1; + (void) sm_insert(B, prow->row_num, prow1->row_num); + } + } + } + } + + return B; +} diff --git a/benchmarks/benchmarks/espresso/irred.c b/benchmarks/benchmarks/espresso/irred.c new file mode 100644 index 0000000..0c49ff3 --- /dev/null +++ b/benchmarks/benchmarks/espresso/irred.c @@ -0,0 +1,431 @@ +#include "espresso.h" + +static void fcube_is_covered(); +static void ftautology(); +static bool ftaut_special_cases(); + + +static int Rp_current; + +/* + * irredundant -- Return a minimal subset of F + */ + +pcover +irredundant(F, D) +pcover F, D; +{ + mark_irredundant(F, D); + return sf_inactive(F); +} + + +/* + * mark_irredundant -- find redundant cubes, and mark them "INACTIVE" + */ + +void +mark_irredundant(F, D) +pcover F, D; +{ + pcover E, Rt, Rp; + pset p, p1, last; + sm_matrix *table; + sm_row *cover; + sm_element *pe; + + /* extract a minimum cover */ + irred_split_cover(F, D, &E, &Rt, &Rp); + table = irred_derive_table(D, E, Rp); + cover = sm_minimum_cover(table, NIL(int), /* heuristic */ 1, /* debug */ 0); + + /* mark the cubes for the result */ + foreach_set(F, last, p) { + RESET(p, ACTIVE); + RESET(p, RELESSEN); + } + foreach_set(E, last, p) { + p1 = GETSET(F, SIZE(p)); + assert(setp_equal(p1, p)); + SET(p1, ACTIVE); + SET(p1, RELESSEN); /* for essen(), mark as rel. ess. */ + } + sm_foreach_row_element(cover, pe) { + p1 = GETSET(F, pe->col_num); + SET(p1, ACTIVE); + } + + if (debug & IRRED) { + printf("# IRRED: F=%d E=%d R=%d Rt=%d Rp=%d Rc=%d Final=%d Bound=%d\n", + F->count, E->count, Rt->count+Rp->count, Rt->count, Rp->count, + cover->length, E->count + cover->length, 0); + } + + free_cover(E); + free_cover(Rt); + free_cover(Rp); + sm_free(table); + sm_row_free(cover); +} + +/* + * irred_split_cover -- find E, Rt, and Rp from the cover F, D + * + * E -- relatively essential cubes + * Rt -- totally redundant cubes + * Rp -- partially redundant cubes + */ + +void +irred_split_cover(F, D, E, Rt, Rp) +pcover F, D; +pcover *E, *Rt, *Rp; +{ + register pcube p, last; + register int index; + pcover R; + pcube *FD, *ED; + + /* number the cubes of F -- these numbers track into E, Rp, Rt, etc. */ + index = 0; + foreach_set(F, last, p) { + PUTSIZE(p, index); + index++; + } + + *E = new_cover(10); + *Rt = new_cover(10); + *Rp = new_cover(10); + R = new_cover(10); + + /* Split F into E and R */ + FD = cube2list(F, D); + foreach_set(F, last, p) { + if (cube_is_covered(FD, p)) { + R = sf_addset(R, p); + } else { + *E = sf_addset(*E, p); + } + if (debug & IRRED1) { + (void) printf("IRRED1: zr=%d ze=%d to-go=%d time=%s\n", + R->count, (*E)->count, F->count - (R->count + (*E)->count), + print_time(ptime())); + } + } + free_cubelist(FD); + + /* Split R into Rt and Rp */ + ED = cube2list(*E, D); + foreach_set(R, last, p) { + if (cube_is_covered(ED, p)) { + *Rt = sf_addset(*Rt, p); + } else { + *Rp = sf_addset(*Rp, p); + } + if (debug & IRRED1) { + (void) printf("IRRED1: zr=%d zrt=%d to-go=%d time=%s\n", + (*Rp)->count, (*Rt)->count, + R->count - ((*Rp)->count +(*Rt)->count), print_time(ptime())); + } + } + free_cubelist(ED); + + free_cover(R); +} + +/* + * irred_derive_table -- given the covers D, E and the set of + * partially redundant primes Rp, build a covering table showing + * possible selections of primes to cover Rp. + */ + +sm_matrix * +irred_derive_table(D, E, Rp) +pcover D, E, Rp; +{ + register pcube last, p, *list; + sm_matrix *table; + int size_last_dominance, i; + + /* Mark each cube in DE as not part of the redundant set */ + foreach_set(D, last, p) { + RESET(p, REDUND); + } + foreach_set(E, last, p) { + RESET(p, REDUND); + } + + /* Mark each cube in Rp as partially redundant */ + foreach_set(Rp, last, p) { + SET(p, REDUND); /* belongs to redundant set */ + } + + /* For each cube in Rp, find ways to cover its minterms */ + list = cube3list(D, E, Rp); + table = sm_alloc(); + size_last_dominance = 0; + i = 0; + foreach_set(Rp, last, p) { + Rp_current = SIZE(p); + fcube_is_covered(list, p, table); + RESET(p, REDUND); /* can now consider this cube redundant */ + if (debug & IRRED1) { + (void) printf("IRRED1: %d of %d to-go=%d, table=%dx%d time=%s\n", + i, Rp->count, Rp->count - i, + table->nrows, table->ncols, print_time(ptime())); + } + /* try to keep memory limits down by reducing table as we go along */ + if (table->nrows - size_last_dominance > 1000) { + (void) sm_row_dominance(table); + size_last_dominance = table->nrows; + if (debug & IRRED1) { + (void) printf("IRRED1: delete redundant rows, now %dx%d\n", + table->nrows, table->ncols); + } + } + i++; + } + free_cubelist(list); + + return table; +} + +/* cube_is_covered -- determine if a cubelist "covers" a single cube */ +bool +cube_is_covered(T, c) +pcube *T, c; +{ + return tautology(cofactor(T,c)); +} + + + +/* tautology -- answer the tautology question for T */ +bool +tautology(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best, result; + static int taut_level = 0; + + if (debug & TAUT) { + debug_print(T, "TAUTOLOGY", taut_level++); + } + + if ((result = taut_special_cases(T)) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, TAUT); + result = tautology(scofactor(T, cl, best)) && + tautology(scofactor(T, cr, best)); + free_cubelist(T); + free_cube(cl); + free_cube(cr); + } + + if (debug & TAUT) { + printf("exit TAUTOLOGY[%d]: %s\n", --taut_level, print_bool(result)); + } + return result; +} + +/* + * taut_special_cases -- check special cases for tautology + */ + +bool +taut_special_cases(T) +pcube *T; /* will be disposed if answer is determined */ +{ + register pcube *T1, *Tsave, p, ceil=cube.temp[0], temp=cube.temp[1]; + pcube *A, *B; + int var; + + /* Check for a row of all 1's which implies tautology */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, T[0])) { + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which implies no tautology */ +start: + INLINEset_copy(ceil, T[0]); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + free_cubelist(T); + return FALSE; + } + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If function is unate (and no row of all 1's), then no tautology */ + if (cdata.vars_unate == cdata.vars_active) { + free_cubelist(T); + return FALSE; + + /* If active in a single variable (and no column of 0's) then tautology */ + } else if (cdata.vars_active == 1) { + free_cubelist(T); + return TRUE; + + /* Check for unate variables, and reduce cover if there are any */ + } else if (cdata.vars_unate != 0) { + /* Form a cube "ceil" with full variables in the unate variables */ + (void) set_copy(ceil, cube.emptyset); + for(var = 0; var < cube.num_vars; var++) { + if (cdata.is_unate[var]) { + INLINEset_or(ceil, ceil, cube.var_mask[var]); + } + } + + /* Save only those cubes that are "full" in all unate variables */ + for(Tsave = T1 = T+2; (p = *T1++) != 0; ) { + if (setp_implies(ceil, set_or(temp, p, T[0]))) { + *Tsave++ = p; + } + } + *Tsave++ = NULL; + T[1] = (pcube) Tsave; + + if (debug & TAUT) { + printf("UNATE_REDUCTION: %d unate variables, reduced to %d\n", + cdata.vars_unate, CUBELISTSIZE(T)); + } + goto start; + + /* Check for component reduction */ + } else if (cdata.var_zeros[cdata.best] < CUBELISTSIZE(T) / 2) { + if (cubelist_partition(T, &A, &B, debug & TAUT) == 0) { + return MAYBE; + } else { + free_cubelist(T); + if (tautology(A)) { + free_cubelist(B); + return TRUE; + } else { + return tautology(B); + } + } + } + + /* We tried as hard as we could, but must recurse from here on */ + return MAYBE; +} + +/* fcube_is_covered -- determine exactly how a cubelist "covers" a cube */ +static void +fcube_is_covered(T, c, table) +pcube *T, c; +sm_matrix *table; +{ + ftautology(cofactor(T,c), table); +} + + +/* ftautology -- find ways to make a tautology */ +static void +ftautology(T, table) +pcube *T; /* T will be disposed of */ +sm_matrix *table; +{ + register pcube cl, cr; + register int best; + static int ftaut_level = 0; + + if (debug & TAUT) { + debug_print(T, "FIND_TAUTOLOGY", ftaut_level++); + } + + if (ftaut_special_cases(T, table) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, TAUT); + + ftautology(scofactor(T, cl, best), table); + ftautology(scofactor(T, cr, best), table); + + free_cubelist(T); + free_cube(cl); + free_cube(cr); + } + + if (debug & TAUT) { + (void) printf("exit FIND_TAUTOLOGY[%d]: table is %d by %d\n", + --ftaut_level, table->nrows, table->ncols); + } +} + +static bool +ftaut_special_cases(T, table) +pcube *T; /* will be disposed if answer is determined */ +sm_matrix *table; +{ + register pcube *T1, *Tsave, p, temp = cube.temp[0], ceil = cube.temp[1]; + int var, rownum; + + /* Check for a row of all 1's in the essential cubes */ + for(T1 = T+2; (p = *T1++) != 0; ) { + if (! TESTP(p, REDUND)) { + if (full_row(p, T[0])) { + /* subspace is covered by essentials -- no new rows for table */ + free_cubelist(T); + return TRUE; + } + } + } + + /* Collect column counts, determine unate variables, etc. */ +start: + massive_count(T); + + /* If function is unate, find the rows of all 1's */ + if (cdata.vars_unate == cdata.vars_active) { + /* find which nonessentials cover this subspace */ + rownum = table->last_row ? table->last_row->row_num+1 : 0; + (void) sm_insert(table, rownum, Rp_current); + for(T1 = T+2; (p = *T1++) != 0; ) { + if (TESTP(p, REDUND)) { + /* See if a redundant cube covers this leaf */ + if (full_row(p, T[0])) { + (void) sm_insert(table, rownum, (int) SIZE(p)); + } + } + } + free_cubelist(T); + return TRUE; + + /* Perform unate reduction if there are any unate variables */ + } else if (cdata.vars_unate != 0) { + /* Form a cube "ceil" with full variables in the unate variables */ + (void) set_copy(ceil, cube.emptyset); + for(var = 0; var < cube.num_vars; var++) { + if (cdata.is_unate[var]) { + INLINEset_or(ceil, ceil, cube.var_mask[var]); + } + } + + /* Save only those cubes that are "full" in all unate variables */ + for(Tsave = T1 = T+2; (p = *T1++) != 0; ) { + if (setp_implies(ceil, set_or(temp, p, T[0]))) { + *Tsave++ = p; + } + } + *Tsave++ = 0; + T[1] = (pcube) Tsave; + + if (debug & TAUT) { + printf("UNATE_REDUCTION: %d unate variables, reduced to %d\n", + cdata.vars_unate, CUBELISTSIZE(T)); + } + goto start; + } + + /* Not much we can do about it */ + return MAYBE; +} diff --git a/benchmarks/benchmarks/espresso/largest.espresso b/benchmarks/benchmarks/espresso/largest.espresso new file mode 100644 index 0000000..53b0157 --- /dev/null +++ b/benchmarks/benchmarks/espresso/largest.espresso @@ -0,0 +1,2812 @@ +.i 16 +.o 40 +0000000000000000 0000000000000000000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000001001100000 0000000001000000011010000000000000000000 +0000001001100101 0000010010000000011010000000000000000000 +0000001001101010 0001010000000000011010000000000000000000 +0000001001101111 0000100000000000011010000000000000000000 +0000001010100000 0000000001000000101010000000000000000000 +0000001010100101 0000010010000000101010000000000000000000 +0000001010101010 0001010000000000101010000000000000000000 +0000001010101111 0000100000000000101010000000000000000000 +0000001000100000 0000000001000000001010000000000000000000 +0000001000100101 0000010010000000001010000000000000000000 +0000001000101010 0001010000000000001010000000000000000000 +0000001000101111 0000100000000000001010000000000000000000 +0000001011100000 0000000001000000111010000000000000000000 +0000001011100101 0000010010000000111010000000000000000000 +0000001011101010 0001010000000000111010000000000000000000 +0000001011101111 0000100000000000111010000000000000000000 +0000001001010000 0000000001000000010110000000000000000000 +0000001001010101 0000010010000000010110000000000000000000 +0000001001011010 0001010000000000010110000000000000000000 +0000001001011111 0000100000000000010110000000000000000000 +0000001010010000 0000000001000000100110000000000000000000 +0000001010010101 0000010010000000100110000000000000000000 +0000001010011010 0001010000000000100110000000000000000000 +0000001010011111 0000100000000000100110000000000000000000 +0000001000010000 0000000001000000000110000000000000000000 +0000001000010101 0000010010000000000110000000000000000000 +0000001000011010 0001010000000000000110000000000000000000 +0000001000011111 0000100000000000000110000000000000000000 +0000001011010000 0000000001000000110110000000000000000000 +0000001011010101 0000010010000000110110000000000000000000 +0000001011011010 0001010000000000110110000000000000000000 +0000001011011111 0000100000000000110110000000000000000000 +0000001001000000 0000000001000000010010000000000000000000 +0000001001000101 0000010010000000010010000000000000000000 +0000001001001010 0001010000000000010010000000000000000000 +0000001001001111 0000100000000000010010000000000000000000 +0000001010000000 0000000001000000100010000000000000000000 +0000001010000101 0000010010000000100010000000000000000000 +0000001010001010 0001010000000000100010000000000000000000 +0000001010001111 0000100000000000100010000000000000000000 +0000001000000000 0000000001000000000010000000000000000000 +0000001000000101 0000010010000000000010000000000000000000 +0000001000001010 0001010000000000000010000000000000000000 +0000001000001111 0000100000000000000010000000000000000000 +0000001011000000 0000000001000000110010000000000000000000 +0000001011000101 0000010010000000110010000000000000000000 +0000001011001010 0001010000000000110010000000000000000000 +0000001011001111 0000100000000000110010000000000000000000 +0000001001110000 0000000001000000011110000000000000000000 +0000001001110101 0000010010000000011110000000000000000000 +0000001001111010 0001010000000000011110000000000000000000 +0000001001111111 0000100000000000011110000000000000000000 +0000001010110000 0000000001000000101110000000000000000000 +0000001010110101 0000010010000000101110000000000000000000 +0000001010111010 0001010000000000101110000000000000000000 +0000001010111111 0000100000000000101110000000000000000000 +0000001000110000 0000000001000000001110000000000000000000 +0000001000110101 0000010010000000001110000000000000000000 +0000001000111010 0001010000000000001110000000000000000000 +0000001000111111 0000100000000000001110000000000000000000 +0000001011110000 0000000001000000111110000000000000000000 +0000001011110101 0000010010000000111110000000000000000000 +0000001011111010 0001010000000000111110000000000000000000 +0000001011111111 0000100000000000111110000000000000000000 +0000001001100100 0000010011000000011010000000000000000000 +0000001001101000 0001010001000000011010000000000000000000 +0000001001101100 0000100001000000011010000000000000000000 +0000001001100001 0000010011000000011010000000000000000000 +0000001001101001 0001010010000000011010000000000000000000 +0000001001101101 0000110010000000011010000000000000000000 +0000001001100010 0001010001000000011010000000000000000000 +0000001001100110 0001010010000000011010000000000000000000 +0000001001101110 0001110000000000011010000000000000000000 +0000001001100011 0000100001000000011010000000000000000000 +0000001001100111 0000110010000000011010000000000000000000 +0000001001101011 0001110000000000011010000000000000000000 +0000001010100100 0000010011000000101010000000000000000000 +0000001010101000 0001010001000000101010000000000000000000 +0000001010101100 0000100001000000101010000000000000000000 +0000001010100001 0000010011000000101010000000000000000000 +0000001010101001 0001010010000000101010000000000000000000 +0000001010101101 0000110010000000101010000000000000000000 +0000001010100010 0001010001000000101010000000000000000000 +0000001010100110 0001010010000000101010000000000000000000 +0000001010101110 0001110000000000101010000000000000000000 +0000001010100011 0000100001000000101010000000000000000000 +0000001010100111 0000110010000000101010000000000000000000 +0000001010101011 0001110000000000101010000000000000000000 +0000001000100100 0000010011000000001010000000000000000000 +0000001000101000 0001010001000000001010000000000000000000 +0000001000101100 0000100001000000001010000000000000000000 +0000001000100001 0000010011000000001010000000000000000000 +0000001000101001 0001010010000000001010000000000000000000 +0000001000101101 0000110010000000001010000000000000000000 +0000001000100010 0001010001000000001010000000000000000000 +0000001000100110 0001010010000000001010000000000000000000 +0000001000101110 0001110000000000001010000000000000000000 +0000001000100011 0000100001000000001010000000000000000000 +0000001000100111 0000110010000000001010000000000000000000 +0000001000101011 0001110000000000001010000000000000000000 +0000001011100100 0000010011000000111010000000000000000000 +0000001011101000 0001010001000000111010000000000000000000 +0000001011101100 0000100001000000111010000000000000000000 +0000001011100001 0000010011000000111010000000000000000000 +0000001011101001 0001010010000000111010000000000000000000 +0000001011101101 0000110010000000111010000000000000000000 +0000001011100010 0001010001000000111010000000000000000000 +0000001011100110 0001010010000000111010000000000000000000 +0000001011101110 0001110000000000111010000000000000000000 +0000001011100011 0000100001000000111010000000000000000000 +0000001011100111 0000110010000000111010000000000000000000 +0000001011101011 0001110000000000111010000000000000000000 +0000001001010100 0000010011000000010110000000000000000000 +0000001001011000 0001010001000000010110000000000000000000 +0000001001011100 0000100001000000010110000000000000000000 +0000001001010001 0000010011000000010110000000000000000000 +0000001001011001 0001010010000000010110000000000000000000 +0000001001011101 0000110010000000010110000000000000000000 +0000001001010010 0001010001000000010110000000000000000000 +0000001001010110 0001010010000000010110000000000000000000 +0000001001011110 0001110000000000010110000000000000000000 +0000001001010011 0000100001000000010110000000000000000000 +0000001001010111 0000110010000000010110000000000000000000 +0000001001011011 0001110000000000010110000000000000000000 +0000001010010100 0000010011000000100110000000000000000000 +0000001010011000 0001010001000000100110000000000000000000 +0000001010011100 0000100001000000100110000000000000000000 +0000001010010001 0000010011000000100110000000000000000000 +0000001010011001 0001010010000000100110000000000000000000 +0000001010011101 0000110010000000100110000000000000000000 +0000001010010010 0001010001000000100110000000000000000000 +0000001010010110 0001010010000000100110000000000000000000 +0000001010011110 0001110000000000100110000000000000000000 +0000001010010011 0000100001000000100110000000000000000000 +0000001010010111 0000110010000000100110000000000000000000 +0000001010011011 0001110000000000100110000000000000000000 +0000001000010100 0000010011000000000110000000000000000000 +0000001000011000 0001010001000000000110000000000000000000 +0000001000011100 0000100001000000000110000000000000000000 +0000001000010001 0000010011000000000110000000000000000000 +0000001000011001 0001010010000000000110000000000000000000 +0000001000011101 0000110010000000000110000000000000000000 +0000001000010010 0001010001000000000110000000000000000000 +0000001000010110 0001010010000000000110000000000000000000 +0000001000011110 0001110000000000000110000000000000000000 +0000001000010011 0000100001000000000110000000000000000000 +0000001000010111 0000110010000000000110000000000000000000 +0000001000011011 0001110000000000000110000000000000000000 +0000001011010100 0000010011000000110110000000000000000000 +0000001011011000 0001010001000000110110000000000000000000 +0000001011011100 0000100001000000110110000000000000000000 +0000001011010001 0000010011000000110110000000000000000000 +0000001011011001 0001010010000000110110000000000000000000 +0000001011011101 0000110010000000110110000000000000000000 +0000001011010010 0001010001000000110110000000000000000000 +0000001011010110 0001010010000000110110000000000000000000 +0000001011011110 0001110000000000110110000000000000000000 +0000001011010011 0000100001000000110110000000000000000000 +0000001011010111 0000110010000000110110000000000000000000 +0000001011011011 0001110000000000110110000000000000000000 +0000001001000100 0000010011000000010010000000000000000000 +0000001001001000 0001010001000000010010000000000000000000 +0000001001001100 0000100001000000010010000000000000000000 +0000001001000001 0000010011000000010010000000000000000000 +0000001001001001 0001010010000000010010000000000000000000 +0000001001001101 0000110010000000010010000000000000000000 +0000001001000010 0001010001000000010010000000000000000000 +0000001001000110 0001010010000000010010000000000000000000 +0000001001001110 0001110000000000010010000000000000000000 +0000001001000011 0000100001000000010010000000000000000000 +0000001001000111 0000110010000000010010000000000000000000 +0000001001001011 0001110000000000010010000000000000000000 +0000001010000100 0000010011000000100010000000000000000000 +0000001010001000 0001010001000000100010000000000000000000 +0000001010001100 0000100001000000100010000000000000000000 +0000001010000001 0000010011000000100010000000000000000000 +0000001010001001 0001010010000000100010000000000000000000 +0000001010001101 0000110010000000100010000000000000000000 +0000001010000010 0001010001000000100010000000000000000000 +0000001010000110 0001010010000000100010000000000000000000 +0000001010001110 0001110000000000100010000000000000000000 +0000001010000011 0000100001000000100010000000000000000000 +0000001010000111 0000110010000000100010000000000000000000 +0000001010001011 0001110000000000100010000000000000000000 +0000001000000100 0000010011000000000010000000000000000000 +0000001000001000 0001010001000000000010000000000000000000 +0000001000001100 0000100001000000000010000000000000000000 +0000001000000001 0000010011000000000010000000000000000000 +0000001000001001 0001010010000000000010000000000000000000 +0000001000001101 0000110010000000000010000000000000000000 +0000001000000010 0001010001000000000010000000000000000000 +0000001000000110 0001010010000000000010000000000000000000 +0000001000001110 0001110000000000000010000000000000000000 +0000001000000011 0000100001000000000010000000000000000000 +0000001000000111 0000110010000000000010000000000000000000 +0000001000001011 0001110000000000000010000000000000000000 +0000001011000100 0000010011000000110010000000000000000000 +0000001011001000 0001010001000000110010000000000000000000 +0000001011001100 0000100001000000110010000000000000000000 +0000001011000001 0000010011000000110010000000000000000000 +0000001011001001 0001010010000000110010000000000000000000 +0000001011001101 0000110010000000110010000000000000000000 +0000001011000010 0001010001000000110010000000000000000000 +0000001011000110 0001010010000000110010000000000000000000 +0000001011001110 0001110000000000110010000000000000000000 +0000001011000011 0000100001000000110010000000000000000000 +0000001011000111 0000110010000000110010000000000000000000 +0000001011001011 0001110000000000110010000000000000000000 +0000001001110100 0000010011000000011110000000000000000000 +0000001001111000 0001010001000000011110000000000000000000 +0000001001111100 0000100001000000011110000000000000000000 +0000001001110001 0000010011000000011110000000000000000000 +0000001001111001 0001010010000000011110000000000000000000 +0000001001111101 0000110010000000011110000000000000000000 +0000001001110010 0001010001000000011110000000000000000000 +0000001001110110 0001010010000000011110000000000000000000 +0000001001111110 0001110000000000011110000000000000000000 +0000001001110011 0000100001000000011110000000000000000000 +0000001001110111 0000110010000000011110000000000000000000 +0000001001111011 0001110000000000011110000000000000000000 +0000001010110100 0000010011000000101110000000000000000000 +0000001010111000 0001010001000000101110000000000000000000 +0000001010111100 0000100001000000101110000000000000000000 +0000001010110001 0000010011000000101110000000000000000000 +0000001010111001 0001010010000000101110000000000000000000 +0000001010111101 0000110010000000101110000000000000000000 +0000001010110010 0001010001000000101110000000000000000000 +0000001010110110 0001010010000000101110000000000000000000 +0000001010111110 0001110000000000101110000000000000000000 +0000001010110011 0000100001000000101110000000000000000000 +0000001010110111 0000110010000000101110000000000000000000 +0000001010111011 0001110000000000101110000000000000000000 +0000001000110100 0000010011000000001110000000000000000000 +0000001000111000 0001010001000000001110000000000000000000 +0000001000111100 0000100001000000001110000000000000000000 +0000001000110001 0000010011000000001110000000000000000000 +0000001000111001 0001010010000000001110000000000000000000 +0000001000111101 0000110010000000001110000000000000000000 +0000001000110010 0001010001000000001110000000000000000000 +0000001000110110 0001010010000000001110000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000001000111110 0001110000000000001110000000000000000000 +0000001000110011 0000100001000000001110000000000000000000 +0000001000110111 0000110010000000001110000000000000000000 +0000001000111011 0001110000000000001110000000000000000000 +0000001011110100 0000010011000000111110000000000000000000 +0000001011111000 0001010001000000111110000000000000000000 +0000001011111100 0000100001000000111110000000000000000000 +0000001011110001 0000010011000000111110000000000000000000 +0000001011111001 0001010010000000111110000000000000000000 +0000001011111101 0000110010000000111110000000000000000000 +0000001011110010 0001010001000000111110000000000000000000 +0000001011110110 0001010010000000111110000000000000000000 +0000001011111110 0001110000000000111110000000000000000000 +0000001011110011 0000100001000000111110000000000000000000 +0000001011110111 0000110010000000111110000000000000000000 +0000001011111011 0001110000000000111110000000000000000000 +0000001101000000 0000000001010000010010000000000000000000 +0000001110000101 0000010010010000100010000000000000000000 +0000001100101010 0001010000010000001010000000000000000000 +0000001100011111 0000100000010000000110000000000000000000 +0000001101000101 0000010010010000010010000000000000000000 +0000001101001010 0001010000010000010010000000000000000000 +0000001101001111 0000100000010000010010000000000000000000 +0000001110000000 0000000001010000100010000000000000000000 +0000001110001010 0001010000010000100010000000000000000000 +0000001110001111 0000100000010000100010000000000000000000 +0000001100100000 0000000001010000001010000000000000000000 +0000001100100101 0000010010010000001010000000000000000000 +0000001100101111 0000100000010000001010000000000000000000 +0000001100010000 0000000001010000000110000000000000000000 +0000001100010101 0000010010010000000110000000000000000000 +0000001100011010 0001010000010000000110000000000000000000 +0000001101000100 0000010011010000010010000000000000000000 +0000001101001000 0001010001010000010010000000000000000000 +0000001101001100 0000100001010000010010000000000000000000 +0000001101000001 0000010011010000010010000000000000000000 +0000001101001001 0001010010010000010010000000000000000000 +0000001101001101 0000110010010000010010000000000000000000 +0000001101000010 0001010001010000010010000000000000000000 +0000001101000110 0001010010010000010010000000000000000000 +0000001101001110 0001110000010000010010000000000000000000 +0000001101000011 0000100001010000010010000000000000000000 +0000001101000111 0000110010010000010010000000000000000000 +0000001101001011 0001110000010000010010000000000000000000 +0000001110000100 0000010011010000100010000000000000000000 +0000001110001000 0001010001010000100010000000000000000000 +0000001110001100 0000100001010000100010000000000000000000 +0000001110000001 0000010011010000100010000000000000000000 +0000001110001001 0001010010010000100010000000000000000000 +0000001110001101 0000110010010000100010000000000000000000 +0000001110000010 0001010001010000100010000000000000000000 +0000001110000110 0001010010010000100010000000000000000000 +0000001110001110 0001110000010000100010000000000000000000 +0000001110000011 0000100001010000100010000000000000000000 +0000001110000111 0000110010010000100010000000000000000000 +0000001110001011 0001110000010000100010000000000000000000 +0000001100100100 0000010011010000001010000000000000000000 +0000001100101000 0001010001010000001010000000000000000000 +0000001100101100 0000100001010000001010000000000000000000 +0000001100100001 0000010011010000001010000000000000000000 +0000001100101001 0001010010010000001010000000000000000000 +0000001100101101 0000110010010000001010000000000000000000 +0000001100100010 0001010001010000001010000000000000000000 +0000001100100110 0001010010010000001010000000000000000000 +0000001100101110 0001110000010000001010000000000000000000 +0000001100100011 0000100001010000001010000000000000000000 +0000001100100111 0000110010010000001010000000000000000000 +0000001100101011 0001110000010000001010000000000000000000 +0000001100010100 0000010011010000000110000000000000000000 +0000001100011000 0001010001010000000110000000000000000000 +0000001100011100 0000100001010000000110000000000000000000 +0000001100010001 0000010011010000000110000000000000000000 +0000001100011001 0001010010010000000110000000000000000000 +0000001100011101 0000110010010000000110000000000000000000 +0000001100010010 0001010001010000000110000000000000000000 +0000001100010110 0001010010010000000110000000000000000000 +0000001100011110 0001110000010000000110000000000000000000 +0000001100010011 0000100001010000000110000000000000000000 +0000001100010111 0000110010010000000110000000000000000000 +0000001100011011 0001110000010000000110000000000000000000 +0000100001100000 0000000001001000011000000000000000000000 +0000100001100101 0000010010001000011000000000000000000000 +0000100001101010 0001010000001000011000000000000000000000 +0000100001101111 0000100000001000011000000000000000000000 +0000100010100000 0000000001001000101000000000000000000000 +0000100010100101 0000010010001000101000000000000000000000 +0000100010101010 0001010000001000101000000000000000000000 +0000100010101111 0000100000001000101000000000000000000000 +0000100000100000 0000000001001000001000000000000000000000 +0000100000100101 0000010010001000001000000000000000000000 +0000100000101010 0001010000001000001000000000000000000000 +0000100000101111 0000100000001000001000000000000000000000 +0000100011100000 0000000001001000111000000000000000000000 +0000100011100101 0000010010001000111000000000000000000000 +0000100011101010 0001010000001000111000000000000000000000 +0000100011101111 0000100000001000111000000000000000000000 +0000100001010000 0000000001001000010100000000000000000000 +0000100001010101 0000010010001000010100000000000000000000 +0000100001011010 0001010000001000010100000000000000000000 +0000100001011111 0000100000001000010100000000000000000000 +0000100010010000 0000000001001000100100000000000000000000 +0000100010010101 0000010010001000100100000000000000000000 +0000100010011010 0001010000001000100100000000000000000000 +0000100010011111 0000100000001000100100000000000000000000 +0000100000010000 0000000001001000000100000000000000000000 +0000100000010101 0000010010001000000100000000000000000000 +0000100000011010 0001010000001000000100000000000000000000 +0000100000011111 0000100000001000000100000000000000000000 +0000100011010000 0000000001001000110100000000000000000000 +0000100011010101 0000010010001000110100000000000000000000 +0000100011011010 0001010000001000110100000000000000000000 +0000100011011111 0000100000001000110100000000000000000000 +0000100001000000 0000000001001000010000000000000000000000 +0000100001000101 0000010010001000010000000000000000000000 +0000100001001010 0001010000001000010000000000000000000000 +0000100001001111 0000100000001000010000000000000000000000 +0000100010000000 0000000001001000100000000000000000000000 +0000100010000101 0000010010001000100000000000000000000000 +0000100010001010 0001010000001000100000000000000000000000 +0000100010001111 0000100000001000100000000000000000000000 +0000100000000000 0000000001001000000000000000000000000000 +0000100000000101 0000010010001000000000000000000000000000 +0000100000001010 0001010000001000000000000000000000000000 +0000100000001111 0000100000001000000000000000000000000000 +0000100011000000 0000000001001000110000000000000000000000 +0000100011000101 0000010010001000110000000000000000000000 +0000100011001010 0001010000001000110000000000000000000000 +0000100011001111 0000100000001000110000000000000000000000 +0000100001110000 0000000001001000011100000000000000000000 +0000100001110101 0000010010001000011100000000000000000000 +0000100001111010 0001010000001000011100000000000000000000 +0000100001111111 0000100000001000011100000000000000000000 +0000100010110000 0000000001001000101100000000000000000000 +0000100010110101 0000010010001000101100000000000000000000 +0000100010111010 0001010000001000101100000000000000000000 +0000100010111111 0000100000001000101100000000000000000000 +0000100000110000 0000000001001000001100000000000000000000 +0000100000110101 0000010010001000001100000000000000000000 +0000100000111010 0001010000001000001100000000000000000000 +0000100000111111 0000100000001000001100000000000000000000 +0000100011110000 0000000001001000111100000000000000000000 +0000100011110101 0000010010001000111100000000000000000000 +0000100011111010 0001010000001000111100000000000000000000 +0000100011111111 0000100000001000111100000000000000000000 +0000100001100100 0000010011001000011000000000000000000000 +0000100001101000 0001010001001000011000000000000000000000 +0000100001101100 0000100001001000011000000000000000000000 +0000100001100001 0000010011001000011000000000000000000000 +0000100001101001 0001010010001000011000000000000000000000 +0000100001101101 0000110010001000011000000000000000000000 +0000100001100010 0001010001001000011000000000000000000000 +0000100001100110 0001010010001000011000000000000000000000 +0000100001101110 0001110000001000011000000000000000000000 +0000100001100011 0000100001001000011000000000000000000000 +0000100001100111 0000110010001000011000000000000000000000 +0000100001101011 0001110000001000011000000000000000000000 +0000100010100100 0000010011001000101000000000000000000000 +0000100010101000 0001010001001000101000000000000000000000 +0000100010101100 0000100001001000101000000000000000000000 +0000100010100001 0000010011001000101000000000000000000000 +0000100010101001 0001010010001000101000000000000000000000 +0000100010101101 0000110010001000101000000000000000000000 +0000100010100010 0001010001001000101000000000000000000000 +0000100010100110 0001010010001000101000000000000000000000 +0000100010101110 0001110000001000101000000000000000000000 +0000100010100011 0000100001001000101000000000000000000000 +0000100010100111 0000110010001000101000000000000000000000 +0000100010101011 0001110000001000101000000000000000000000 +0000100000100100 0000010011001000001000000000000000000000 +0000100000101000 0001010001001000001000000000000000000000 +0000100000101100 0000100001001000001000000000000000000000 +0000100000100001 0000010011001000001000000000000000000000 +0000100000101001 0001010010001000001000000000000000000000 +0000100000101101 0000110010001000001000000000000000000000 +0000100000100010 0001010001001000001000000000000000000000 +0000100000100110 0001010010001000001000000000000000000000 +0000100000101110 0001110000001000001000000000000000000000 +0000100000100011 0000100001001000001000000000000000000000 +0000100000100111 0000110010001000001000000000000000000000 +0000100000101011 0001110000001000001000000000000000000000 +0000100011100100 0000010011001000111000000000000000000000 +0000100011101000 0001010001001000111000000000000000000000 +0000100011101100 0000100001001000111000000000000000000000 +0000100011100001 0000010011001000111000000000000000000000 +0000100011101001 0001010010001000111000000000000000000000 +0000100011101101 0000110010001000111000000000000000000000 +0000100011100010 0001010001001000111000000000000000000000 +0000100011100110 0001010010001000111000000000000000000000 +0000100011101110 0001110000001000111000000000000000000000 +0000100011100011 0000100001001000111000000000000000000000 +0000100011100111 0000110010001000111000000000000000000000 +0000100011101011 0001110000001000111000000000000000000000 +0000100001010100 0000010011001000010100000000000000000000 +0000100001011000 0001010001001000010100000000000000000000 +0000100001011100 0000100001001000010100000000000000000000 +0000100001010001 0000010011001000010100000000000000000000 +0000100001011001 0001010010001000010100000000000000000000 +0000100001011101 0000110010001000010100000000000000000000 +0000100001010010 0001010001001000010100000000000000000000 +0000100001010110 0001010010001000010100000000000000000000 +0000100001011110 0001110000001000010100000000000000000000 +0000100001010011 0000100001001000010100000000000000000000 +0000100001010111 0000110010001000010100000000000000000000 +0000100001011011 0001110000001000010100000000000000000000 +0000100010010100 0000010011001000100100000000000000000000 +0000100010011000 0001010001001000100100000000000000000000 +0000100010011100 0000100001001000100100000000000000000000 +0000100010010001 0000010011001000100100000000000000000000 +0000100010011001 0001010010001000100100000000000000000000 +0000100010011101 0000110010001000100100000000000000000000 +0000100010010010 0001010001001000100100000000000000000000 +0000100010010110 0001010010001000100100000000000000000000 +0000100010011110 0001110000001000100100000000000000000000 +0000100010010011 0000100001001000100100000000000000000000 +0000100010010111 0000110010001000100100000000000000000000 +0000100010011011 0001110000001000100100000000000000000000 +0000100000010100 0000010011001000000100000000000000000000 +0000100000011000 0001010001001000000100000000000000000000 +0000100000011100 0000100001001000000100000000000000000000 +0000100000010001 0000010011001000000100000000000000000000 +0000100000011001 0001010010001000000100000000000000000000 +0000100000011101 0000110010001000000100000000000000000000 +0000100000010010 0001010001001000000100000000000000000000 +0000100000010110 0001010010001000000100000000000000000000 +0000100000011110 0001110000001000000100000000000000000000 +0000100000010011 0000100001001000000100000000000000000000 +0000100000010111 0000110010001000000100000000000000000000 +0000100000011011 0001110000001000000100000000000000000000 +0000100011010100 0000010011001000110100000000000000000000 +0000100011011000 0001010001001000110100000000000000000000 +0000100011011100 0000100001001000110100000000000000000000 +0000100011010001 0000010011001000110100000000000000000000 +0000100011011001 0001010010001000110100000000000000000000 +0000100011011101 0000110010001000110100000000000000000000 +0000100011010010 0001010001001000110100000000000000000000 +0000100011010110 0001010010001000110100000000000000000000 +0000100011011110 0001110000001000110100000000000000000000 +0000100011010011 0000100001001000110100000000000000000000 +0000100011010111 0000110010001000110100000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000100011011011 0001110000001000110100000000000000000000 +0000100001000100 0000010011001000010000000000000000000000 +0000100001001000 0001010001001000010000000000000000000000 +0000100001001100 0000100001001000010000000000000000000000 +0000100001000001 0000010011001000010000000000000000000000 +0000100001001001 0001010010001000010000000000000000000000 +0000100001001101 0000110010001000010000000000000000000000 +0000100001000010 0001010001001000010000000000000000000000 +0000100001000110 0001010010001000010000000000000000000000 +0000100001001110 0001110000001000010000000000000000000000 +0000100001000011 0000100001001000010000000000000000000000 +0000100001000111 0000110010001000010000000000000000000000 +0000100001001011 0001110000001000010000000000000000000000 +0000100010000100 0000010011001000100000000000000000000000 +0000100010001000 0001010001001000100000000000000000000000 +0000100010001100 0000100001001000100000000000000000000000 +0000100010000001 0000010011001000100000000000000000000000 +0000100010001001 0001010010001000100000000000000000000000 +0000100010001101 0000110010001000100000000000000000000000 +0000100010000010 0001010001001000100000000000000000000000 +0000100010000110 0001010010001000100000000000000000000000 +0000100010001110 0001110000001000100000000000000000000000 +0000100010000011 0000100001001000100000000000000000000000 +0000100010000111 0000110010001000100000000000000000000000 +0000100010001011 0001110000001000100000000000000000000000 +0000100000000100 0000010011001000000000000000000000000000 +0000100000001000 0001010001001000000000000000000000000000 +0000100000001100 0000100001001000000000000000000000000000 +0000100000000001 0000010011001000000000000000000000000000 +0000100000001001 0001010010001000000000000000000000000000 +0000100000001101 0000110010001000000000000000000000000000 +0000100000000010 0001010001001000000000000000000000000000 +0000100000000110 0001010010001000000000000000000000000000 +0000100000001110 0001110000001000000000000000000000000000 +0000100000000011 0000100001001000000000000000000000000000 +0000100000000111 0000110010001000000000000000000000000000 +0000100000001011 0001110000001000000000000000000000000000 +0000100011000100 0000010011001000110000000000000000000000 +0000100011001000 0001010001001000110000000000000000000000 +0000100011001100 0000100001001000110000000000000000000000 +0000100011000001 0000010011001000110000000000000000000000 +0000100011001001 0001010010001000110000000000000000000000 +0000100011001101 0000110010001000110000000000000000000000 +0000100011000010 0001010001001000110000000000000000000000 +0000100011000110 0001010010001000110000000000000000000000 +0000100011001110 0001110000001000110000000000000000000000 +0000100011000011 0000100001001000110000000000000000000000 +0000100011000111 0000110010001000110000000000000000000000 +0000100011001011 0001110000001000110000000000000000000000 +0000100001110100 0000010011001000011100000000000000000000 +0000100001111000 0001010001001000011100000000000000000000 +0000100001111100 0000100001001000011100000000000000000000 +0000100001110001 0000010011001000011100000000000000000000 +0000100001111001 0001010010001000011100000000000000000000 +0000100001111101 0000110010001000011100000000000000000000 +0000100001110010 0001010001001000011100000000000000000000 +0000100001110110 0001010010001000011100000000000000000000 +0000100001111110 0001110000001000011100000000000000000000 +0000100001110011 0000100001001000011100000000000000000000 +0000100001110111 0000110010001000011100000000000000000000 +0000100001111011 0001110000001000011100000000000000000000 +0000100010110100 0000010011001000101100000000000000000000 +0000100010111000 0001010001001000101100000000000000000000 +0000100010111100 0000100001001000101100000000000000000000 +0000100010110001 0000010011001000101100000000000000000000 +0000100010111001 0001010010001000101100000000000000000000 +0000100010111101 0000110010001000101100000000000000000000 +0000100010110010 0001010001001000101100000000000000000000 +0000100010110110 0001010010001000101100000000000000000000 +0000100010111110 0001110000001000101100000000000000000000 +0000100010110011 0000100001001000101100000000000000000000 +0000100010110111 0000110010001000101100000000000000000000 +0000100010111011 0001110000001000101100000000000000000000 +0000100000110100 0000010011001000001100000000000000000000 +0000100000111000 0001010001001000001100000000000000000000 +0000100000111100 0000100001001000001100000000000000000000 +0000100000110001 0000010011001000001100000000000000000000 +0000100000111001 0001010010001000001100000000000000000000 +0000100000111101 0000110010001000001100000000000000000000 +0000100000110010 0001010001001000001100000000000000000000 +0000100000110110 0001010010001000001100000000000000000000 +0000100000111110 0001110000001000001100000000000000000000 +0000100000110011 0000100001001000001100000000000000000000 +0000100000110111 0000110010001000001100000000000000000000 +0000100000111011 0001110000001000001100000000000000000000 +0000100011110100 0000010011001000111100000000000000000000 +0000100011111000 0001010001001000111100000000000000000000 +0000100011111100 0000100001001000111100000000000000000000 +0000100011110001 0000010011001000111100000000000000000000 +0000100011111001 0001010010001000111100000000000000000000 +0000100011111101 0000110010001000111100000000000000000000 +0000100011110010 0001010001001000111100000000000000000000 +0000100011110110 0001010010001000111100000000000000000000 +0000100011111110 0001110000001000111100000000000000000000 +0000100011110011 0000100001001000111100000000000000000000 +0000100011110111 0000110010001000111100000000000000000000 +0000100011111011 0001110000001000111100000000000000000000 +0000100000000000 0000000001001000000000000000000000000000 +0000100000000101 0000010010001000000000000000000000000000 +0000100000001010 0001010000001000000000000000000000000000 +0000100000001111 0000100000001000000000000000000000000000 +0000100000000100 0000010011001000000000000000000000000000 +0000100000001000 0001010001001000000000000000000000000000 +0000100000001100 0000100001001000000000000000000000000000 +0000100000000001 0000010011001000000000000000000000000000 +0000100000001001 0001010010001000000000000000000000000000 +0000100000001101 0000110010001000000000000000000000000000 +0000100000000010 0001010001001000000000000000000000000000 +0000100000000110 0001010010001000000000000000000000000000 +0000100000001110 0001110000001000000000000000000000000000 +0000100000000011 0000100001001000000000000000000000000000 +0000100000000111 0000110010001000000000000000000000000000 +0000100000001011 0001110000001000000000000000000000000000 +0000010011101010 0001010000000000111011000000000000000000 +0000010011011111 0000100000000000110111000000000000000000 +0000010011100000 0000000001000000111011000000000000000000 +0000010011100101 0000010010000000111011000000000000000000 +0000010011101111 0000100000000000111011000000000000000000 +0000010011010000 0000000001000000110111000000000000000000 +0000010011010101 0000010010000000110111000000000000000000 +0000010011011010 0001010000000000110111000000000000000000 +0000010011100100 0000010011000000111011000000000000000000 +0000010011101000 0001010001000000111011000000000000000000 +0000010011101100 0000100001000000111011000000000000000000 +0000010011100001 0000010011000000111011000000000000000000 +0000010011101001 0001010010000000111011000000000000000000 +0000010011101101 0000110010000000111011000000000000000000 +0000010011100010 0001010001000000111011000000000000000000 +0000010011100110 0001010010000000111011000000000000000000 +0000010011101110 0001110000000000111011000000000000000000 +0000010011100011 0000100001000000111011000000000000000000 +0000010011100111 0000110010000000111011000000000000000000 +0000010011101011 0001110000000000111011000000000000000000 +0000010011010100 0000010011000000110111000000000000000000 +0000010011011000 0001010001000000110111000000000000000000 +0000010011011100 0000100001000000110111000000000000000000 +0000010011010001 0000010011000000110111000000000000000000 +0000010011011001 0001010010000000110111000000000000000000 +0000010011011101 0000110010000000110111000000000000000000 +0000010011010010 0001010001000000110111000000000000000000 +0000010011010110 0001010010000000110111000000000000000000 +0000010011011110 0001110000000000110111000000000000000000 +0000010011010011 0000100001000000110111000000000000000000 +0000010011010111 0000110010000000110111000000000000000000 +0000010011011011 0001110000000000110111000000000000000000 +0000001001110000 0000000001000000011110000000000000000000 +0000001010110101 0000010010000000101110000000000000000000 +0000001011101010 0001010000000000111010000000000000000000 +0000001011011111 0000100000000000110110000000000000000000 +0000001001110101 0000010010000000011110000000000000000000 +0000001001111010 0001010000000000011110000000000000000000 +0000001001111111 0000100000000000011110000000000000000000 +0000001010110000 0000000001000000101110000000000000000000 +0000001010111010 0001010000000000101110000000000000000000 +0000001010111111 0000100000000000101110000000000000000000 +0000001011100000 0000000001000000111010000000000000000000 +0000001011100101 0000010010000000111010000000000000000000 +0000001011101111 0000100000000000111010000000000000000000 +0000001011010000 0000000001000000110110000000000000000000 +0000001011010101 0000010010000000110110000000000000000000 +0000001011011010 0001010000000000110110000000000000000000 +0000001001110100 0000010011000000011110000000000000000000 +0000001001111000 0001010001000000011110000000000000000000 +0000001001111100 0000100001000000011110000000000000000000 +0000001001110001 0000010011000000011110000000000000000000 +0000001001111001 0001010010000000011110000000000000000000 +0000001001111101 0000110010000000011110000000000000000000 +0000001001110010 0001010001000000011110000000000000000000 +0000001001110110 0001010010000000011110000000000000000000 +0000001001111110 0001110000000000011110000000000000000000 +0000001001110011 0000100001000000011110000000000000000000 +0000001001110111 0000110010000000011110000000000000000000 +0000001001111011 0001110000000000011110000000000000000000 +0000001010110100 0000010011000000101110000000000000000000 +0000001010111000 0001010001000000101110000000000000000000 +0000001010111100 0000100001000000101110000000000000000000 +0000001010110001 0000010011000000101110000000000000000000 +0000001010111001 0001010010000000101110000000000000000000 +0000001010111101 0000110010000000101110000000000000000000 +0000001010110010 0001010001000000101110000000000000000000 +0000001010110110 0001010010000000101110000000000000000000 +0000001010111110 0001110000000000101110000000000000000000 +0000001010110011 0000100001000000101110000000000000000000 +0000001010110111 0000110010000000101110000000000000000000 +0000001010111011 0001110000000000101110000000000000000000 +0000001011100100 0000010011000000111010000000000000000000 +0000001011101000 0001010001000000111010000000000000000000 +0000001011101100 0000100001000000111010000000000000000000 +0000001011100001 0000010011000000111010000000000000000000 +0000001011101001 0001010010000000111010000000000000000000 +0000001011101101 0000110010000000111010000000000000000000 +0000001011100010 0001010001000000111010000000000000000000 +0000001011100110 0001010010000000111010000000000000000000 +0000001011101110 0001110000000000111010000000000000000000 +0000001011100011 0000100001000000111010000000000000000000 +0000001011100111 0000110010000000111010000000000000000000 +0000001011101011 0001110000000000111010000000000000000000 +0000001011010100 0000010011000000110110000000000000000000 +0000001011011000 0001010001000000110110000000000000000000 +0000001011011100 0000100001000000110110000000000000000000 +0000001011010001 0000010011000000110110000000000000000000 +0000001011011001 0001010010000000110110000000000000000000 +0000001011011101 0000110010000000110110000000000000000000 +0000001011010010 0001010001000000110110000000000000000000 +0000001011010110 0001010010000000110110000000000000000000 +0000001011011110 0001110000000000110110000000000000000000 +0000001011010011 0000100001000000110110000000000000000000 +0000001011010111 0000110010000000110110000000000000000000 +0000001011011011 0001110000000000110110000000000000000000 +0000100101000101 0000010010000100010000000000000000000000 +0000100101001010 0001010000000100010000000000000000000000 +0000100101001111 0000100000000100010000000000000000000000 +0000100110000000 0000000001000100100000000000000000000000 +0000100110001010 0001010000000100100000000000000000000000 +0000100110001111 0000100000000100100000000000000000000000 +0000100100100000 0000000001000100001000000000000000000000 +0000100100100101 0000010010000100001000000000000000000000 +0000100100101111 0000100000000100001000000000000000000000 +0000100100010000 0000000001000100000100000000000000000000 +0000100100010101 0000010010000100000100000000000000000000 +0000100100011010 0001010000000100000100000000000000000000 +0000100101001001 0001010010000100010000000000000000000000 +0000100101001101 0000110010000100010000000000000000000000 +0000100101000110 0001010010000100010000000000000000000000 +0000100101001110 0001110000000100010000000000000000000000 +0000100101000111 0000110010000100010000000000000000000000 +0000100101001011 0001110000000100010000000000000000000000 +0000100110001000 0001010001000100100000000000000000000000 +0000100110001100 0000100001000100100000000000000000000000 +0000100110000010 0001010001000100100000000000000000000000 +0000100110001110 0001110000000100100000000000000000000000 +0000100110000011 0000100001000100100000000000000000000000 +0000100110001011 0001110000000100100000000000000000000000 +0000100100100100 0000010011000100001000000000000000000000 +0000100100101100 0000100001000100001000000000000000000000 +0000100100100001 0000010011000100001000000000000000000000 +0000100100101101 0000110010000100001000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000100100100011 0000100001000100001000000000000000000000 +0000100100100111 0000110010000100001000000000000000000000 +0000100100010100 0000010011000100000100000000000000000000 +0000100100011000 0001010001000100000100000000000000000000 +0000100100010001 0000010011000100000100000000000000000000 +0000100100011001 0001010010000100000100000000000000000000 +0000100100010010 0001010001000100000100000000000000000000 +0000100100010110 0001010010000100000100000000000000000000 +0000111001101010 0001010000000000011000000010000000000000 +0000111010101010 0001010000000000101000000010000000000000 +0000111000101010 0001010000000000001000000010000000000000 +0000111011101010 0001010000000000111000000010000000000000 +0000111001011111 0000100000000000010100000010000000000000 +0000111010011111 0000100000000000100100000010000000000000 +0000111000011111 0000100000000000000100000010000000000000 +0000111011011111 0000100000000000110100000010000000000000 +0000111001101000 0001010001000000011000000010000000000000 +0000111001101001 0001010010000000011000000010000000000000 +0000111001100010 0001010001000000011000000010000000000000 +0000111001100110 0001010010000000011000000010000000000000 +0000111001101110 0001110000000000011000000010000000000000 +0000111001101011 0001110000000000011000000010000000000000 +0000111010101000 0001010001000000101000000010000000000000 +0000111010101001 0001010010000000101000000010000000000000 +0000111010100010 0001010001000000101000000010000000000000 +0000111010100110 0001010010000000101000000010000000000000 +0000111010101110 0001110000000000101000000010000000000000 +0000111010101011 0001110000000000101000000010000000000000 +0000111001011100 0000100001000000010100000010000000000000 +0000111001011101 0000110010000000010100000010000000000000 +0000111001011110 0001110000000000010100000010000000000000 +0000111001010011 0000100001000000010100000010000000000000 +0000111001010111 0000110010000000010100000010000000000000 +0000111001011011 0001110000000000010100000010000000000000 +0000111010011100 0000100001000000100100000010000000000000 +0000111010011101 0000110010000000100100000010000000000000 +0000111010011110 0001110000000000100100000010000000000000 +0000111010010011 0000100001000000100100000010000000000000 +0000111010010111 0000110010000000100100000010000000000000 +0000111010011011 0001110000000000100100000010000000000000 +0000110101100000 0000000001000000011000010100000000101000 +0000110101100101 0000010010000000011000010100000000101000 +0000110101101010 0001010000000000011000010100000000101000 +0000110101101111 0000100000000000011000010100000000101000 +0000110110100000 0000000001000000101000010100000000101000 +0000110110100101 0000010010000000101000010100000000101000 +0000110110101010 0001010000000000101000010100000000101000 +0000110110101111 0000100000000000101000010100000000101000 +0000110100100000 0000000001000000001000010100000000101000 +0000110100100101 0000010010000000001000010100000000101000 +0000110100101010 0001010000000000001000010100000000101000 +0000110100101111 0000100000000000001000010100000000101000 +0000110111100000 0000000001000000111000010100000000101000 +0000110111100101 0000010010000000111000010100000000101000 +0000110111101010 0001010000000000111000010100000000101000 +0000110111101111 0000100000000000111000010100000000101000 +0000110101010000 0000000001000000010100010100000000101000 +0000110101010101 0000010010000000010100010100000000101000 +0000110101011010 0001010000000000010100010100000000101000 +0000110101011111 0000100000000000010100010100000000101000 +0000110110010000 0000000001000000100100010100000000101000 +0000110110010101 0000010010000000100100010100000000101000 +0000110110011010 0001010000000000100100010100000000101000 +0000110110011111 0000100000000000100100010100000000101000 +0000110100010000 0000000001000000000100010100000000101000 +0000110100010101 0000010010000000000100010100000000101000 +0000110100011010 0001010000000000000100010100000000101000 +0000110100011111 0000100000000000000100010100000000101000 +0000110111010000 0000000001000000110100010100000000101000 +0000110111010101 0000010010000000110100010100000000101000 +0000110111011010 0001010000000000110100010100000000101000 +0000110111011111 0000100000000000110100010100000000101000 +0000110101000000 0000000001000000010000010100000000101000 +0000110101000101 0000010010000000010000010100000000101000 +0000110101001010 0001010000000000010000010100000000101000 +0000110101001111 0000100000000000010000010100000000101000 +0000110110000000 0000000001000000100000010100000000101000 +0000110110000101 0000010010000000100000010100000000101000 +0000110110001010 0001010000000000100000010100000000101000 +0000110110001111 0000100000000000100000010100000000101000 +0000110100000000 0000000001000000000000010100000000101000 +0000110100000101 0000010010000000000000010100000000101000 +0000110100001010 0001010000000000000000010100000000101000 +0000110100001111 0000100000000000000000010100000000101000 +0000110111000000 0000000001000000110000010100000000101000 +0000110111000101 0000010010000000110000010100000000101000 +0000110111001010 0001010000000000110000010100000000101000 +0000110111001111 0000100000000000110000010100000000101000 +0000110101110000 0000000001000000011100010100000000101000 +0000110101110101 0000010010000000011100010100000000101000 +0000110101111010 0001010000000000011100010100000000101000 +0000110101111111 0000100000000000011100010100000000101000 +0000110110110000 0000000001000000101100010100000000101000 +0000110110110101 0000010010000000101100010100000000101000 +0000110110111010 0001010000000000101100010100000000101000 +0000110110111111 0000100000000000101100010100000000101000 +0000110100110000 0000000001000000001100010100000000101000 +0000110100110101 0000010010000000001100010100000000101000 +0000110100111010 0001010000000000001100010100000000101000 +0000110100111111 0000100000000000001100010100000000101000 +0000110111110000 0000000001000000111100010100000000101000 +0000110111110101 0000010010000000111100010100000000101000 +0000110111111010 0001010000000000111100010100000000101000 +0000110111111111 0000100000000000111100010100000000101000 +0000110101100100 0000010011000000011000010100000000101000 +0000110101101000 0001010001000000011000010100000000101000 +0000110101101100 0000100001000000011000010100000000101000 +0000110101100001 0000010011000000011000010100000000101000 +0000110101101001 0001010010000000011000010100000000101000 +0000110101101101 0000110010000000011000010100000000101000 +0000110101100010 0001010001000000011000010100000000101000 +0000110101100110 0001010010000000011000010100000000101000 +0000110101101110 0001110000000000011000010100000000101000 +0000110101100011 0000100001000000011000010100000000101000 +0000110101100111 0000110010000000011000010100000000101000 +0000110101101011 0001110000000000011000010100000000101000 +0000110110100100 0000010011000000101000010100000000101000 +0000110110101000 0001010001000000101000010100000000101000 +0000110110101100 0000100001000000101000010100000000101000 +0000110110100001 0000010011000000101000010100000000101000 +0000110110101001 0001010010000000101000010100000000101000 +0000110110101101 0000110010000000101000010100000000101000 +0000110110100010 0001010001000000101000010100000000101000 +0000110110100110 0001010010000000101000010100000000101000 +0000110110101110 0001110000000000101000010100000000101000 +0000110110100011 0000100001000000101000010100000000101000 +0000110110100111 0000110010000000101000010100000000101000 +0000110110101011 0001110000000000101000010100000000101000 +0000110100100100 0000010011000000001000010100000000101000 +0000110100101000 0001010001000000001000010100000000101000 +0000110100101100 0000100001000000001000010100000000101000 +0000110100100001 0000010011000000001000010100000000101000 +0000110100101001 0001010010000000001000010100000000101000 +0000110100101101 0000110010000000001000010100000000101000 +0000110100100010 0001010001000000001000010100000000101000 +0000110100100110 0001010010000000001000010100000000101000 +0000110100101110 0001110000000000001000010100000000101000 +0000110100100011 0000100001000000001000010100000000101000 +0000110100100111 0000110010000000001000010100000000101000 +0000110100101011 0001110000000000001000010100000000101000 +0000110111100100 0000010011000000111000010100000000101000 +0000110111101000 0001010001000000111000010100000000101000 +0000110111101100 0000100001000000111000010100000000101000 +0000110111100001 0000010011000000111000010100000000101000 +0000110111101001 0001010010000000111000010100000000101000 +0000110111101101 0000110010000000111000010100000000101000 +0000110111100010 0001010001000000111000010100000000101000 +0000110111100110 0001010010000000111000010100000000101000 +0000110111101110 0001110000000000111000010100000000101000 +0000110111100011 0000100001000000111000010100000000101000 +0000110111100111 0000110010000000111000010100000000101000 +0000110111101011 0001110000000000111000010100000000101000 +0000110101010100 0000010011000000010100010100000000101000 +0000110101011000 0001010001000000010100010100000000101000 +0000110101011100 0000100001000000010100010100000000101000 +0000110101010001 0000010011000000010100010100000000101000 +0000110101011001 0001010010000000010100010100000000101000 +0000110101011101 0000110010000000010100010100000000101000 +0000110101010010 0001010001000000010100010100000000101000 +0000110101010110 0001010010000000010100010100000000101000 +0000110101011110 0001110000000000010100010100000000101000 +0000110101010011 0000100001000000010100010100000000101000 +0000110101010111 0000110010000000010100010100000000101000 +0000110101011011 0001110000000000010100010100000000101000 +0000110110010100 0000010011000000100100010100000000101000 +0000110110011000 0001010001000000100100010100000000101000 +0000110110011100 0000100001000000100100010100000000101000 +0000110110010001 0000010011000000100100010100000000101000 +0000110110011001 0001010010000000100100010100000000101000 +0000110110011101 0000110010000000100100010100000000101000 +0000110110010010 0001010001000000100100010100000000101000 +0000110110010110 0001010010000000100100010100000000101000 +0000110110011110 0001110000000000100100010100000000101000 +0000110110010011 0000100001000000100100010100000000101000 +0000110110010111 0000110010000000100100010100000000101000 +0000110110011011 0001110000000000100100010100000000101000 +0000110100010100 0000010011000000000100010100000000101000 +0000110100011000 0001010001000000000100010100000000101000 +0000110100011100 0000100001000000000100010100000000101000 +0000110100010001 0000010011000000000100010100000000101000 +0000110100011001 0001010010000000000100010100000000101000 +0000110100011101 0000110010000000000100010100000000101000 +0000110100010010 0001010001000000000100010100000000101000 +0000110100010110 0001010010000000000100010100000000101000 +0000110100011110 0001110000000000000100010100000000101000 +0000110100010011 0000100001000000000100010100000000101000 +0000110100010111 0000110010000000000100010100000000101000 +0000110100011011 0001110000000000000100010100000000101000 +0000110111010100 0000010011000000110100010100000000101000 +0000110111011000 0001010001000000110100010100000000101000 +0000110111011100 0000100001000000110100010100000000101000 +0000110111010001 0000010011000000110100010100000000101000 +0000110111011001 0001010010000000110100010100000000101000 +0000110111011101 0000110010000000110100010100000000101000 +0000110111010010 0001010001000000110100010100000000101000 +0000110111010110 0001010010000000110100010100000000101000 +0000110111011110 0001110000000000110100010100000000101000 +0000110111010011 0000100001000000110100010100000000101000 +0000110111010111 0000110010000000110100010100000000101000 +0000110111011011 0001110000000000110100010100000000101000 +0000110101000100 0000010011000000010000010100000000101000 +0000110101001000 0001010001000000010000010100000000101000 +0000110101001100 0000100001000000010000010100000000101000 +0000110101000001 0000010011000000010000010100000000101000 +0000110101001001 0001010010000000010000010100000000101000 +0000110101001101 0000110010000000010000010100000000101000 +0000110101000010 0001010001000000010000010100000000101000 +0000110101000110 0001010010000000010000010100000000101000 +0000110101001110 0001110000000000010000010100000000101000 +0000110101000011 0000100001000000010000010100000000101000 +0000110101000111 0000110010000000010000010100000000101000 +0000110101001011 0001110000000000010000010100000000101000 +0000110110000100 0000010011000000100000010100000000101000 +0000110110001000 0001010001000000100000010100000000101000 +0000110110001100 0000100001000000100000010100000000101000 +0000110110000001 0000010011000000100000010100000000101000 +0000110110001001 0001010010000000100000010100000000101000 +0000110110001101 0000110010000000100000010100000000101000 +0000110110000010 0001010001000000100000010100000000101000 +0000110110000110 0001010010000000100000010100000000101000 +0000110110001110 0001110000000000100000010100000000101000 +0000110110000011 0000100001000000100000010100000000101000 +0000110110000111 0000110010000000100000010100000000101000 +0000110110001011 0001110000000000100000010100000000101000 +0000110100000100 0000010011000000000000010100000000101000 +0000110100001000 0001010001000000000000010100000000101000 +0000110100001100 0000100001000000000000010100000000101000 +0000110100000001 0000010011000000000000010100000000101000 +0000110100001001 0001010010000000000000010100000000101000 +0000110100001101 0000110010000000000000010100000000101000 +0000110100000010 0001010001000000000000010100000000101000 +0000110100000110 0001010010000000000000010100000000101000 +0000110100001110 0001110000000000000000010100000000101000 +0000110100000011 0000100001000000000000010100000000101000 +0000110100000111 0000110010000000000000010100000000101000 +0000110100001011 0001110000000000000000010100000000101000 +0000110111000100 0000010011000000110000010100000000101000 +0000110111001000 0001010001000000110000010100000000101000 +0000110111001100 0000100001000000110000010100000000101000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000110111000001 0000010011000000110000010100000000101000 +0000110111001001 0001010010000000110000010100000000101000 +0000110111001101 0000110010000000110000010100000000101000 +0000110111000010 0001010001000000110000010100000000101000 +0000110111000110 0001010010000000110000010100000000101000 +0000110111001110 0001110000000000110000010100000000101000 +0000110111000011 0000100001000000110000010100000000101000 +0000110111000111 0000110010000000110000010100000000101000 +0000110111001011 0001110000000000110000010100000000101000 +0000110101110100 0000010011000000011100010100000000101000 +0000110101111000 0001010001000000011100010100000000101000 +0000110101111100 0000100001000000011100010100000000101000 +0000110101110001 0000010011000000011100010100000000101000 +0000110101111001 0001010010000000011100010100000000101000 +0000110101111101 0000110010000000011100010100000000101000 +0000110101110010 0001010001000000011100010100000000101000 +0000110101110110 0001010010000000011100010100000000101000 +0000110101111110 0001110000000000011100010100000000101000 +0000110101110011 0000100001000000011100010100000000101000 +0000110101110111 0000110010000000011100010100000000101000 +0000110101111011 0001110000000000011100010100000000101000 +0000110110110100 0000010011000000101100010100000000101000 +0000110110111000 0001010001000000101100010100000000101000 +0000110110111100 0000100001000000101100010100000000101000 +0000110110110001 0000010011000000101100010100000000101000 +0000110110111001 0001010010000000101100010100000000101000 +0000110110111101 0000110010000000101100010100000000101000 +0000110110110010 0001010001000000101100010100000000101000 +0000110110110110 0001010010000000101100010100000000101000 +0000110110111110 0001110000000000101100010100000000101000 +0000110110110011 0000100001000000101100010100000000101000 +0000110110110111 0000110010000000101100010100000000101000 +0000110110111011 0001110000000000101100010100000000101000 +0000110100110100 0000010011000000001100010100000000101000 +0000110100111000 0001010001000000001100010100000000101000 +0000110100111100 0000100001000000001100010100000000101000 +0000110100110001 0000010011000000001100010100000000101000 +0000110100111001 0001010010000000001100010100000000101000 +0000110100111101 0000110010000000001100010100000000101000 +0000110100110010 0001010001000000001100010100000000101000 +0000110100110110 0001010010000000001100010100000000101000 +0000110100111110 0001110000000000001100010100000000101000 +0000110100110011 0000100001000000001100010100000000101000 +0000110100110111 0000110010000000001100010100000000101000 +0000110100111011 0001110000000000001100010100000000101000 +0000110111110100 0000010011000000111100010100000000101000 +0000110111111000 0001010001000000111100010100000000101000 +0000110111111100 0000100001000000111100010100000000101000 +0000110111110001 0000010011000000111100010100000000101000 +0000110111111001 0001010010000000111100010100000000101000 +0000110111111101 0000110010000000111100010100000000101000 +0000110111110010 0001010001000000111100010100000000101000 +0000110111110110 0001010010000000111100010100000000101000 +0000110111111110 0001110000000000111100010100000000101000 +0000110111110011 0000100001000000111100010100000000101000 +0000110111110111 0000110010000000111100010100000000101000 +0000110111111011 0001110000000000111100010100000000101000 +0000010001000000 0000000001000000010011000000000000000000 +0000010010000101 0000010010000000100011000000000000000000 +0000010001000101 0000010010000000010011000000000000000000 +0000010001001010 0001010000000000010011000000000000000000 +0000010001001111 0000100000000000010011000000000000000000 +0000010010000000 0000000001000000100011000000000000000000 +0000010010001010 0001010000000000100011000000000000000000 +0000010010001111 0000100000000000100011000000000000000000 +0000010001000100 0000010011000000010011000000000000000000 +0000010001001000 0001010001000000010011000000000000000000 +0000010001001100 0000100001000000010011000000000000000000 +0000010001000001 0000010011000000010011000000000000000000 +0000010001001001 0001010010000000010011000000000000000000 +0000010001001101 0000110010000000010011000000000000000000 +0000010001000010 0001010001000000010011000000000000000000 +0000010001000110 0001010010000000010011000000000000000000 +0000010001001110 0001110000000000010011000000000000000000 +0000010001000011 0000100001000000010011000000000000000000 +0000010001000111 0000110010000000010011000000000000000000 +0000010001001011 0001110000000000010011000000000000000000 +0000010010000100 0000010011000000100011000000000000000000 +0000010010001000 0001010001000000100011000000000000000000 +0000010010001100 0000100001000000100011000000000000000000 +0000010010000001 0000010011000000100011000000000000000000 +0000010010001001 0001010010000000100011000000000000000000 +0000010010001101 0000110010000000100011000000000000000000 +0000010010000010 0001010001000000100011000000000000000000 +0000010010000110 0001010010000000100011000000000000000000 +0000010010001110 0001110000000000100011000000000000000000 +0000010010000011 0000100001000000100011000000000000000000 +0000010010000111 0000110010000000100011000000000000000000 +0000010010001011 0001110000000000100011000000000000000000 +000001010100---- 0001010000000000010011000000000000000000 +000001011000---- 0001010000000000100011000000000000000000 +0000010001100000 0000000001000000011011000000000000000000 +0000010001100101 0000010010000000011011000000000000000000 +0000010001101010 0001010000000000011011000000000000000000 +0000010001101111 0000100000000000011011000000000000000000 +0000010010100000 0000000001000000101011000000000000000000 +0000010010100101 0000010010000000101011000000000000000000 +0000010010101010 0001010000000000101011000000000000000000 +0000010010101111 0000100000000000101011000000000000000000 +0000010000100000 0000000001000000001011000000000000000000 +0000010000100101 0000010010000000001011000000000000000000 +0000010000101010 0001010000000000001011000000000000000000 +0000010000101111 0000100000000000001011000000000000000000 +0000010011100000 0000000001000000111011000000000000000000 +0000010011100101 0000010010000000111011000000000000000000 +0000010011101010 0001010000000000111011000000000000000000 +0000010011101111 0000100000000000111011000000000000000000 +0000010001010000 0000000001000000010111000000000000000000 +0000010001010101 0000010010000000010111000000000000000000 +0000010001011010 0001010000000000010111000000000000000000 +0000010001011111 0000100000000000010111000000000000000000 +0000010010010000 0000000001000000100111000000000000000000 +0000010010010101 0000010010000000100111000000000000000000 +0000010010011010 0001010000000000100111000000000000000000 +0000010010011111 0000100000000000100111000000000000000000 +0000010000010000 0000000001000000000111000000000000000000 +0000010000010101 0000010010000000000111000000000000000000 +0000010000011010 0001010000000000000111000000000000000000 +0000010000011111 0000100000000000000111000000000000000000 +0000010011010000 0000000001000000110111000000000000000000 +0000010011010101 0000010010000000110111000000000000000000 +0000010011011010 0001010000000000110111000000000000000000 +0000010011011111 0000100000000000110111000000000000000000 +0000010001000000 0000000001000000010011000000000000000000 +0000010001000101 0000010010000000010011000000000000000000 +0000010001001010 0001010000000000010011000000000000000000 +0000010001001111 0000100000000000010011000000000000000000 +0000010010000000 0000000001000000100011000000000000000000 +0000010010000101 0000010010000000100011000000000000000000 +0000010010001010 0001010000000000100011000000000000000000 +0000010010001111 0000100000000000100011000000000000000000 +0000010000000000 0000000001000000000011000000000000000000 +0000010000000101 0000010010000000000011000000000000000000 +0000010000001010 0001010000000000000011000000000000000000 +0000010000001111 0000100000000000000011000000000000000000 +0000010011000000 0000000001000000110011000000000000000000 +0000010011000101 0000010010000000110011000000000000000000 +0000010011001010 0001010000000000110011000000000000000000 +0000010011001111 0000100000000000110011000000000000000000 +0000010001110000 0000000001000000011111000000000000000000 +0000010001110101 0000010010000000011111000000000000000000 +0000010001111010 0001010000000000011111000000000000000000 +0000010001111111 0000100000000000011111000000000000000000 +0000010010110000 0000000001000000101111000000000000000000 +0000010010110101 0000010010000000101111000000000000000000 +0000010010111010 0001010000000000101111000000000000000000 +0000010010111111 0000100000000000101111000000000000000000 +0000010000110000 0000000001000000001111000000000000000000 +0000010000110101 0000010010000000001111000000000000000000 +0000010000111010 0001010000000000001111000000000000000000 +0000010000111111 0000100000000000001111000000000000000000 +0000010011110000 0000000001000000111111000000000000000000 +0000010011110101 0000010010000000111111000000000000000000 +0000010011111010 0001010000000000111111000000000000000000 +0000010011111111 0000100000000000111111000000000000000000 +0000010001100100 0000010011000000011011000000000000000000 +0000010001101000 0001010001000000011011000000000000000000 +0000010001101100 0000100001000000011011000000000000000000 +0000010001100001 0000010011000000011011000000000000000000 +0000010001101001 0001010010000000011011000000000000000000 +0000010001101101 0000110010000000011011000000000000000000 +0000010001100010 0001010001000000011011000000000000000000 +0000010001100110 0001010010000000011011000000000000000000 +0000010001101110 0001110000000000011011000000000000000000 +0000010001100011 0000100001000000011011000000000000000000 +0000010001100111 0000110010000000011011000000000000000000 +0000010001101011 0001110000000000011011000000000000000000 +0000010010100100 0000010011000000101011000000000000000000 +0000010010101000 0001010001000000101011000000000000000000 +0000010010101100 0000100001000000101011000000000000000000 +0000010010100001 0000010011000000101011000000000000000000 +0000010010101001 0001010010000000101011000000000000000000 +0000010010101101 0000110010000000101011000000000000000000 +0000010010100010 0001010001000000101011000000000000000000 +0000010010100110 0001010010000000101011000000000000000000 +0000010010101110 0001110000000000101011000000000000000000 +0000010010100011 0000100001000000101011000000000000000000 +0000010010100111 0000110010000000101011000000000000000000 +0000010010101011 0001110000000000101011000000000000000000 +0000010000100100 0000010011000000001011000000000000000000 +0000010000101000 0001010001000000001011000000000000000000 +0000010000101100 0000100001000000001011000000000000000000 +0000010000100001 0000010011000000001011000000000000000000 +0000010000101001 0001010010000000001011000000000000000000 +0000010000101101 0000110010000000001011000000000000000000 +0000010000100010 0001010001000000001011000000000000000000 +0000010000100110 0001010010000000001011000000000000000000 +0000010000101110 0001110000000000001011000000000000000000 +0000010000100011 0000100001000000001011000000000000000000 +0000010000100111 0000110010000000001011000000000000000000 +0000010000101011 0001110000000000001011000000000000000000 +0000010011100100 0000010011000000111011000000000000000000 +0000010011101000 0001010001000000111011000000000000000000 +0000010011101100 0000100001000000111011000000000000000000 +0000010011100001 0000010011000000111011000000000000000000 +0000010011101001 0001010010000000111011000000000000000000 +0000010011101101 0000110010000000111011000000000000000000 +0000010011100010 0001010001000000111011000000000000000000 +0000010011100110 0001010010000000111011000000000000000000 +0000010011101110 0001110000000000111011000000000000000000 +0000010011100011 0000100001000000111011000000000000000000 +0000010011100111 0000110010000000111011000000000000000000 +0000010011101011 0001110000000000111011000000000000000000 +0000010001010100 0000010011000000010111000000000000000000 +0000010001011000 0001010001000000010111000000000000000000 +0000010001011100 0000100001000000010111000000000000000000 +0000010001010001 0000010011000000010111000000000000000000 +0000010001011001 0001010010000000010111000000000000000000 +0000010001011101 0000110010000000010111000000000000000000 +0000010001010010 0001010001000000010111000000000000000000 +0000010001010110 0001010010000000010111000000000000000000 +0000010001011110 0001110000000000010111000000000000000000 +0000010001010011 0000100001000000010111000000000000000000 +0000010001010111 0000110010000000010111000000000000000000 +0000010001011011 0001110000000000010111000000000000000000 +0000010010010100 0000010011000000100111000000000000000000 +0000010010011000 0001010001000000100111000000000000000000 +0000010010011100 0000100001000000100111000000000000000000 +0000010010010001 0000010011000000100111000000000000000000 +0000010010011001 0001010010000000100111000000000000000000 +0000010010011101 0000110010000000100111000000000000000000 +0000010010010010 0001010001000000100111000000000000000000 +0000010010010110 0001010010000000100111000000000000000000 +0000010010011110 0001110000000000100111000000000000000000 +0000010010010011 0000100001000000100111000000000000000000 +0000010010010111 0000110010000000100111000000000000000000 +0000010010011011 0001110000000000100111000000000000000000 +0000010000010100 0000010011000000000111000000000000000000 +0000010000011000 0001010001000000000111000000000000000000 +0000010000011100 0000100001000000000111000000000000000000 +0000010000010001 0000010011000000000111000000000000000000 +0000010000011001 0001010010000000000111000000000000000000 +0000010000011101 0000110010000000000111000000000000000000 +0000010000010010 0001010001000000000111000000000000000000 +0000010000010110 0001010010000000000111000000000000000000 +0000010000011110 0001110000000000000111000000000000000000 +0000010000010011 0000100001000000000111000000000000000000 +0000010000010111 0000110010000000000111000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000010000011011 0001110000000000000111000000000000000000 +0000010011010100 0000010011000000110111000000000000000000 +0000010011011000 0001010001000000110111000000000000000000 +0000010011011100 0000100001000000110111000000000000000000 +0000010011010001 0000010011000000110111000000000000000000 +0000010011011001 0001010010000000110111000000000000000000 +0000010011011101 0000110010000000110111000000000000000000 +0000010011010010 0001010001000000110111000000000000000000 +0000010011010110 0001010010000000110111000000000000000000 +0000010011011110 0001110000000000110111000000000000000000 +0000010011010011 0000100001000000110111000000000000000000 +0000010011010111 0000110010000000110111000000000000000000 +0000010011011011 0001110000000000110111000000000000000000 +0000010001000100 0000010011000000010011000000000000000000 +0000010001001000 0001010001000000010011000000000000000000 +0000010001001100 0000100001000000010011000000000000000000 +0000010001000001 0000010011000000010011000000000000000000 +0000010001001001 0001010010000000010011000000000000000000 +0000010001001101 0000110010000000010011000000000000000000 +0000010001000010 0001010001000000010011000000000000000000 +0000010001000110 0001010010000000010011000000000000000000 +0000010001001110 0001110000000000010011000000000000000000 +0000010001000011 0000100001000000010011000000000000000000 +0000010001000111 0000110010000000010011000000000000000000 +0000010001001011 0001110000000000010011000000000000000000 +0000010010000100 0000010011000000100011000000000000000000 +0000010010001000 0001010001000000100011000000000000000000 +0000010010001100 0000100001000000100011000000000000000000 +0000010010000001 0000010011000000100011000000000000000000 +0000010010001001 0001010010000000100011000000000000000000 +0000010010001101 0000110010000000100011000000000000000000 +0000010010000010 0001010001000000100011000000000000000000 +0000010010000110 0001010010000000100011000000000000000000 +0000010010001110 0001110000000000100011000000000000000000 +0000010010000011 0000100001000000100011000000000000000000 +0000010010000111 0000110010000000100011000000000000000000 +0000010010001011 0001110000000000100011000000000000000000 +0000010000000100 0000010011000000000011000000000000000000 +0000010000001000 0001010001000000000011000000000000000000 +0000010000001100 0000100001000000000011000000000000000000 +0000010000000001 0000010011000000000011000000000000000000 +0000010000001001 0001010010000000000011000000000000000000 +0000010000001101 0000110010000000000011000000000000000000 +0000010000000010 0001010001000000000011000000000000000000 +0000010000000110 0001010010000000000011000000000000000000 +0000010000001110 0001110000000000000011000000000000000000 +0000010000000011 0000100001000000000011000000000000000000 +0000010000000111 0000110010000000000011000000000000000000 +0000010000001011 0001110000000000000011000000000000000000 +0000010011000100 0000010011000000110011000000000000000000 +0000010011001000 0001010001000000110011000000000000000000 +0000010011001100 0000100001000000110011000000000000000000 +0000010011000001 0000010011000000110011000000000000000000 +0000010011001001 0001010010000000110011000000000000000000 +0000010011001101 0000110010000000110011000000000000000000 +0000010011000010 0001010001000000110011000000000000000000 +0000010011000110 0001010010000000110011000000000000000000 +0000010011001110 0001110000000000110011000000000000000000 +0000010011000011 0000100001000000110011000000000000000000 +0000010011000111 0000110010000000110011000000000000000000 +0000010011001011 0001110000000000110011000000000000000000 +0000010001110100 0000010011000000011111000000000000000000 +0000010001111000 0001010001000000011111000000000000000000 +0000010001111100 0000100001000000011111000000000000000000 +0000010001110001 0000010011000000011111000000000000000000 +0000010001111001 0001010010000000011111000000000000000000 +0000010001111101 0000110010000000011111000000000000000000 +0000010001110010 0001010001000000011111000000000000000000 +0000010001110110 0001010010000000011111000000000000000000 +0000010001111110 0001110000000000011111000000000000000000 +0000010001110011 0000100001000000011111000000000000000000 +0000010001110111 0000110010000000011111000000000000000000 +0000010001111011 0001110000000000011111000000000000000000 +0000010010110100 0000010011000000101111000000000000000000 +0000010010111000 0001010001000000101111000000000000000000 +0000010010111100 0000100001000000101111000000000000000000 +0000010010110001 0000010011000000101111000000000000000000 +0000010010111001 0001010010000000101111000000000000000000 +0000010010111101 0000110010000000101111000000000000000000 +0000010010110010 0001010001000000101111000000000000000000 +0000010010110110 0001010010000000101111000000000000000000 +0000010010111110 0001110000000000101111000000000000000000 +0000010010110011 0000100001000000101111000000000000000000 +0000010010110111 0000110010000000101111000000000000000000 +0000010010111011 0001110000000000101111000000000000000000 +0000010000110100 0000010011000000001111000000000000000000 +0000010000111000 0001010001000000001111000000000000000000 +0000010000111100 0000100001000000001111000000000000000000 +0000010000110001 0000010011000000001111000000000000000000 +0000010000111001 0001010010000000001111000000000000000000 +0000010000111101 0000110010000000001111000000000000000000 +0000010000110010 0001010001000000001111000000000000000000 +0000010000110110 0001010010000000001111000000000000000000 +0000010000111110 0001110000000000001111000000000000000000 +0000010000110011 0000100001000000001111000000000000000000 +0000010000110111 0000110010000000001111000000000000000000 +0000010000111011 0001110000000000001111000000000000000000 +0000010011110100 0000010011000000111111000000000000000000 +0000010011111000 0001010001000000111111000000000000000000 +0000010011111100 0000100001000000111111000000000000000000 +0000010011110001 0000010011000000111111000000000000000000 +0000010011111001 0001010010000000111111000000000000000000 +0000010011111101 0000110010000000111111000000000000000000 +0000010011110010 0001010001000000111111000000000000000000 +0000010011110110 0001010010000000111111000000000000000000 +0000010011111110 0001110000000000111111000000000000000000 +0000010011110011 0000100001000000111111000000000000000000 +0000010011110111 0000110010000000111111000000000000000000 +0000010011111011 0001110000000000111111000000000000000000 +000001010110---- 0001010000000000011011000000000000000000 +000001011010---- 0001010000000000101011000000000000000000 +000001010101---- 0000100000000000010111000000000000000000 +000001011001---- 0000100000000000100111000000000000000000 +000001010100---- 0001010000000000010011000000000000000000 +000001011000---- 0001010000000000100011000000000000000000 +000001010111---- 0000100000000000011111000000000000000000 +000001011011---- 0000100000000000101111000000000000000000 +0000111101100000 0000000001100000011000010100000000101000 +0000111101100101 0000010010100000011000010100000000101000 +0000111101101010 0001010000100000011000010100000000101000 +0000111101101111 0000100000100000011000010100000000101000 +0000111110100000 0000000001100000101000010100000000101000 +0000111110100101 0000010010100000101000010100000000101000 +0000111110101010 0001010000100000101000010100000000101000 +0000111110101111 0000100000100000101000010100000000101000 +0000111100100000 0000000001100000001000010100000000101000 +0000111100100101 0000010010100000001000010100000000101000 +0000111100101010 0001010000100000001000010100000000101000 +0000111100101111 0000100000100000001000010100000000101000 +0000111111100000 0000000001100000111000010100000000101000 +0000111111100101 0000010010100000111000010100000000101000 +0000111111101010 0001010000100000111000010100000000101000 +0000111111101111 0000100000100000111000010100000000101000 +0000111101010000 0000000001100000010100010100000000101000 +0000111101010101 0000010010100000010100010100000000101000 +0000111101011010 0001010000100000010100010100000000101000 +0000111101011111 0000100000100000010100010100000000101000 +0000111110010000 0000000001100000100100010100000000101000 +0000111110010101 0000010010100000100100010100000000101000 +0000111110011010 0001010000100000100100010100000000101000 +0000111110011111 0000100000100000100100010100000000101000 +0000111100010000 0000000001100000000100010100000000101000 +0000111100010101 0000010010100000000100010100000000101000 +0000111100011010 0001010000100000000100010100000000101000 +0000111100011111 0000100000100000000100010100000000101000 +0000111111010000 0000000001100000110100010100000000101000 +0000111111010101 0000010010100000110100010100000000101000 +0000111111011010 0001010000100000110100010100000000101000 +0000111111011111 0000100000100000110100010100000000101000 +0000111101000000 0000000001100000010000010100000000101000 +0000111101000101 0000010010100000010000010100000000101000 +0000111101001010 0001010000100000010000010100000000101000 +0000111101001111 0000100000100000010000010100000000101000 +0000111110000000 0000000001100000100000010100000000101000 +0000111110000101 0000010010100000100000010100000000101000 +0000111110001010 0001010000100000100000010100000000101000 +0000111110001111 0000100000100000100000010100000000101000 +0000111100000000 0000000001100000000000010100000000101000 +0000111100000101 0000010010100000000000010100000000101000 +0000111100001010 0001010000100000000000010100000000101000 +0000111100001111 0000100000100000000000010100000000101000 +0000111111000000 0000000001100000110000010100000000101000 +0000111111000101 0000010010100000110000010100000000101000 +0000111111001010 0001010000100000110000010100000000101000 +0000111111001111 0000100000100000110000010100000000101000 +0000111101110000 0000000001100000011100010100000000101000 +0000111101110101 0000010010100000011100010100000000101000 +0000111101111010 0001010000100000011100010100000000101000 +0000111101111111 0000100000100000011100010100000000101000 +0000111110110000 0000000001100000101100010100000000101000 +0000111110110101 0000010010100000101100010100000000101000 +0000111110111010 0001010000100000101100010100000000101000 +0000111110111111 0000100000100000101100010100000000101000 +0000111100110000 0000000001100000001100010100000000101000 +0000111100110101 0000010010100000001100010100000000101000 +0000111100111010 0001010000100000001100010100000000101000 +0000111100111111 0000100000100000001100010100000000101000 +0000111111110000 0000000001100000111100010100000000101000 +0000111111110101 0000010010100000111100010100000000101000 +0000111111111010 0001010000100000111100010100000000101000 +0000111111111111 0000100000100000111100010100000000101000 +0000111101100100 0000010011100000011000010100000000101000 +0000111101101000 0001010001100000011000010100000000101000 +0000111101101100 0000100001100000011000010100000000101000 +0000111101100001 0000010011100000011000010100000000101000 +0000111101101001 0001010010100000011000010100000000101000 +0000111101101101 0000110010100000011000010100000000101000 +0000111101100010 0001010001100000011000010100000000101000 +0000111101100110 0001010010100000011000010100000000101000 +0000111101101110 0001110000100000011000010100000000101000 +0000111101100011 0000100001100000011000010100000000101000 +0000111101100111 0000110010100000011000010100000000101000 +0000111101101011 0001110000100000011000010100000000101000 +0000111110100100 0000010011100000101000010100000000101000 +0000111110101000 0001010001100000101000010100000000101000 +0000111110101100 0000100001100000101000010100000000101000 +0000111110100001 0000010011100000101000010100000000101000 +0000111110101001 0001010010100000101000010100000000101000 +0000111110101101 0000110010100000101000010100000000101000 +0000111110100010 0001010001100000101000010100000000101000 +0000111110100110 0001010010100000101000010100000000101000 +0000111110101110 0001110000100000101000010100000000101000 +0000111110100011 0000100001100000101000010100000000101000 +0000111110100111 0000110010100000101000010100000000101000 +0000111110101011 0001110000100000101000010100000000101000 +0000111100100100 0000010011100000001000010100000000101000 +0000111100101000 0001010001100000001000010100000000101000 +0000111100101100 0000100001100000001000010100000000101000 +0000111100100001 0000010011100000001000010100000000101000 +0000111100101001 0001010010100000001000010100000000101000 +0000111100101101 0000110010100000001000010100000000101000 +0000111100100010 0001010001100000001000010100000000101000 +0000111100100110 0001010010100000001000010100000000101000 +0000111100101110 0001110000100000001000010100000000101000 +0000111100100011 0000100001100000001000010100000000101000 +0000111100100111 0000110010100000001000010100000000101000 +0000111100101011 0001110000100000001000010100000000101000 +0000111111100100 0000010011100000111000010100000000101000 +0000111111101000 0001010001100000111000010100000000101000 +0000111111101100 0000100001100000111000010100000000101000 +0000111111100001 0000010011100000111000010100000000101000 +0000111111101001 0001010010100000111000010100000000101000 +0000111111101101 0000110010100000111000010100000000101000 +0000111111100010 0001010001100000111000010100000000101000 +0000111111100110 0001010010100000111000010100000000101000 +0000111111101110 0001110000100000111000010100000000101000 +0000111111100011 0000100001100000111000010100000000101000 +0000111111100111 0000110010100000111000010100000000101000 +0000111111101011 0001110000100000111000010100000000101000 +0000111101010100 0000010011100000010100010100000000101000 +0000111101011000 0001010001100000010100010100000000101000 +0000111101011100 0000100001100000010100010100000000101000 +0000111101010001 0000010011100000010100010100000000101000 +0000111101011001 0001010010100000010100010100000000101000 +0000111101011101 0000110010100000010100010100000000101000 +0000111101010010 0001010001100000010100010100000000101000 +0000111101010110 0001010010100000010100010100000000101000 +0000111101011110 0001110000100000010100010100000000101000 +0000111101010011 0000100001100000010100010100000000101000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000111101010111 0000110010100000010100010100000000101000 +0000111101011011 0001110000100000010100010100000000101000 +0000111110010100 0000010011100000100100010100000000101000 +0000111110011000 0001010001100000100100010100000000101000 +0000111110011100 0000100001100000100100010100000000101000 +0000111110010001 0000010011100000100100010100000000101000 +0000111110011001 0001010010100000100100010100000000101000 +0000111110011101 0000110010100000100100010100000000101000 +0000111110010010 0001010001100000100100010100000000101000 +0000111110010110 0001010010100000100100010100000000101000 +0000111110011110 0001110000100000100100010100000000101000 +0000111110010011 0000100001100000100100010100000000101000 +0000111110010111 0000110010100000100100010100000000101000 +0000111110011011 0001110000100000100100010100000000101000 +0000111100010100 0000010011100000000100010100000000101000 +0000111100011000 0001010001100000000100010100000000101000 +0000111100011100 0000100001100000000100010100000000101000 +0000111100010001 0000010011100000000100010100000000101000 +0000111100011001 0001010010100000000100010100000000101000 +0000111100011101 0000110010100000000100010100000000101000 +0000111100010010 0001010001100000000100010100000000101000 +0000111100010110 0001010010100000000100010100000000101000 +0000111100011110 0001110000100000000100010100000000101000 +0000111100010011 0000100001100000000100010100000000101000 +0000111100010111 0000110010100000000100010100000000101000 +0000111100011011 0001110000100000000100010100000000101000 +0000111111010100 0000010011100000110100010100000000101000 +0000111111011000 0001010001100000110100010100000000101000 +0000111111011100 0000100001100000110100010100000000101000 +0000111111010001 0000010011100000110100010100000000101000 +0000111111011001 0001010010100000110100010100000000101000 +0000111111011101 0000110010100000110100010100000000101000 +0000111111010010 0001010001100000110100010100000000101000 +0000111111010110 0001010010100000110100010100000000101000 +0000111111011110 0001110000100000110100010100000000101000 +0000111111010011 0000100001100000110100010100000000101000 +0000111111010111 0000110010100000110100010100000000101000 +0000111111011011 0001110000100000110100010100000000101000 +0000111101000100 0000010011100000010000010100000000101000 +0000111101001000 0001010001100000010000010100000000101000 +0000111101001100 0000100001100000010000010100000000101000 +0000111101000001 0000010011100000010000010100000000101000 +0000111101001001 0001010010100000010000010100000000101000 +0000111101001101 0000110010100000010000010100000000101000 +0000111101000010 0001010001100000010000010100000000101000 +0000111101000110 0001010010100000010000010100000000101000 +0000111101001110 0001110000100000010000010100000000101000 +0000111101000011 0000100001100000010000010100000000101000 +0000111101000111 0000110010100000010000010100000000101000 +0000111101001011 0001110000100000010000010100000000101000 +0000111110000100 0000010011100000100000010100000000101000 +0000111110001000 0001010001100000100000010100000000101000 +0000111110001100 0000100001100000100000010100000000101000 +0000111110000001 0000010011100000100000010100000000101000 +0000111110001001 0001010010100000100000010100000000101000 +0000111110001101 0000110010100000100000010100000000101000 +0000111110000010 0001010001100000100000010100000000101000 +0000111110000110 0001010010100000100000010100000000101000 +0000111110001110 0001110000100000100000010100000000101000 +0000111110000011 0000100001100000100000010100000000101000 +0000111110000111 0000110010100000100000010100000000101000 +0000111110001011 0001110000100000100000010100000000101000 +0000111100000100 0000010011100000000000010100000000101000 +0000111100001000 0001010001100000000000010100000000101000 +0000111100001100 0000100001100000000000010100000000101000 +0000111100000001 0000010011100000000000010100000000101000 +0000111100001001 0001010010100000000000010100000000101000 +0000111100001101 0000110010100000000000010100000000101000 +0000111100000010 0001010001100000000000010100000000101000 +0000111100000110 0001010010100000000000010100000000101000 +0000111100001110 0001110000100000000000010100000000101000 +0000111100000011 0000100001100000000000010100000000101000 +0000111100000111 0000110010100000000000010100000000101000 +0000111100001011 0001110000100000000000010100000000101000 +0000111111000100 0000010011100000110000010100000000101000 +0000111111001000 0001010001100000110000010100000000101000 +0000111111001100 0000100001100000110000010100000000101000 +0000111111000001 0000010011100000110000010100000000101000 +0000111111001001 0001010010100000110000010100000000101000 +0000111111001101 0000110010100000110000010100000000101000 +0000111111000010 0001010001100000110000010100000000101000 +0000111111000110 0001010010100000110000010100000000101000 +0000111111001110 0001110000100000110000010100000000101000 +0000111111000011 0000100001100000110000010100000000101000 +0000111111000111 0000110010100000110000010100000000101000 +0000111111001011 0001110000100000110000010100000000101000 +0000111101110100 0000010011100000011100010100000000101000 +0000111101111000 0001010001100000011100010100000000101000 +0000111101111100 0000100001100000011100010100000000101000 +0000111101110001 0000010011100000011100010100000000101000 +0000111101111001 0001010010100000011100010100000000101000 +0000111101111101 0000110010100000011100010100000000101000 +0000111101110010 0001010001100000011100010100000000101000 +0000111101110110 0001010010100000011100010100000000101000 +0000111101111110 0001110000100000011100010100000000101000 +0000111101110011 0000100001100000011100010100000000101000 +0000111101110111 0000110010100000011100010100000000101000 +0000111101111011 0001110000100000011100010100000000101000 +0000111110110100 0000010011100000101100010100000000101000 +0000111110111000 0001010001100000101100010100000000101000 +0000111110111100 0000100001100000101100010100000000101000 +0000111110110001 0000010011100000101100010100000000101000 +0000111110111001 0001010010100000101100010100000000101000 +0000111110111101 0000110010100000101100010100000000101000 +0000111110110010 0001010001100000101100010100000000101000 +0000111110110110 0001010010100000101100010100000000101000 +0000111110111110 0001110000100000101100010100000000101000 +0000111110110011 0000100001100000101100010100000000101000 +0000111110110111 0000110010100000101100010100000000101000 +0000111110111011 0001110000100000101100010100000000101000 +0000111100110100 0000010011100000001100010100000000101000 +0000111100111000 0001010001100000001100010100000000101000 +0000111100111100 0000100001100000001100010100000000101000 +0000111100110001 0000010011100000001100010100000000101000 +0000111100111001 0001010010100000001100010100000000101000 +0000111100111101 0000110010100000001100010100000000101000 +0000111100110010 0001010001100000001100010100000000101000 +0000111100110110 0001010010100000001100010100000000101000 +0000111100111110 0001110000100000001100010100000000101000 +0000111100110011 0000100001100000001100010100000000101000 +0000111100110111 0000110010100000001100010100000000101000 +0000111100111011 0001110000100000001100010100000000101000 +0000111111110100 0000010011100000111100010100000000101000 +0000111111111000 0001010001100000111100010100000000101000 +0000111111111100 0000100001100000111100010100000000101000 +0000111111110001 0000010011100000111100010100000000101000 +0000111111111001 0001010010100000111100010100000000101000 +0000111111111101 0000110010100000111100010100000000101000 +0000111111110010 0001010001100000111100010100000000101000 +0000111111110110 0001010010100000111100010100000000101000 +0000111111111110 0001110000100000111100010100000000101000 +0000111111110011 0000100001100000111100010100000000101000 +0000111111110111 0000110010100000111100010100000000101000 +0000111111111011 0001110000100000111100010100000000101000 +0000100101100000 0000000001000100011000000000000000000000 +0000100101100101 0000010010000100011000000000000000000000 +0000100101101010 0001010000000100011000000000000000000000 +0000100101101111 0000100000000100011000000000000000000000 +0000100110100000 0000000001000100101000000000000000000000 +0000100110100101 0000010010000100101000000000000000000000 +0000100110101010 0001010000000100101000000000000000000000 +0000100110101111 0000100000000100101000000000000000000000 +0000100100100000 0000000001000100001000000000000000000000 +0000100100100101 0000010010000100001000000000000000000000 +0000100100101010 0001010000000100001000000000000000000000 +0000100100101111 0000100000000100001000000000000000000000 +0000100111100000 0000000001000100111000000000000000000000 +0000100111100101 0000010010000100111000000000000000000000 +0000100111101010 0001010000000100111000000000000000000000 +0000100111101111 0000100000000100111000000000000000000000 +0000100101010000 0000000001000100010100000000000000000000 +0000100101010101 0000010010000100010100000000000000000000 +0000100101011010 0001010000000100010100000000000000000000 +0000100101011111 0000100000000100010100000000000000000000 +0000100110010000 0000000001000100100100000000000000000000 +0000100110010101 0000010010000100100100000000000000000000 +0000100110011010 0001010000000100100100000000000000000000 +0000100110011111 0000100000000100100100000000000000000000 +0000100100010000 0000000001000100000100000000000000000000 +0000100100010101 0000010010000100000100000000000000000000 +0000100100011010 0001010000000100000100000000000000000000 +0000100100011111 0000100000000100000100000000000000000000 +0000100111010000 0000000001000100110100000000000000000000 +0000100111010101 0000010010000100110100000000000000000000 +0000100111011010 0001010000000100110100000000000000000000 +0000100111011111 0000100000000100110100000000000000000000 +0000100101000000 0000000001000100010000000000000000000000 +0000100101000101 0000010010000100010000000000000000000000 +0000100101001010 0001010000000100010000000000000000000000 +0000100101001111 0000100000000100010000000000000000000000 +0000100110000000 0000000001000100100000000000000000000000 +0000100110000101 0000010010000100100000000000000000000000 +0000100110001010 0001010000000100100000000000000000000000 +0000100110001111 0000100000000100100000000000000000000000 +0000100100000000 0000000001000100000000000000000000000000 +0000100100000101 0000010010000100000000000000000000000000 +0000100100001010 0001010000000100000000000000000000000000 +0000100100001111 0000100000000100000000000000000000000000 +0000100111000000 0000000001000100110000000000000000000000 +0000100111000101 0000010010000100110000000000000000000000 +0000100111001010 0001010000000100110000000000000000000000 +0000100111001111 0000100000000100110000000000000000000000 +0000100101110000 0000000001000100011100000000000000000000 +0000100101110101 0000010010000100011100000000000000000000 +0000100101111010 0001010000000100011100000000000000000000 +0000100101111111 0000100000000100011100000000000000000000 +0000100110110000 0000000001000100101100000000000000000000 +0000100110110101 0000010010000100101100000000000000000000 +0000100110111010 0001010000000100101100000000000000000000 +0000100110111111 0000100000000100101100000000000000000000 +0000100100110000 0000000001000100001100000000000000000000 +0000100100110101 0000010010000100001100000000000000000000 +0000100100111010 0001010000000100001100000000000000000000 +0000100100111111 0000100000000100001100000000000000000000 +0000100111110000 0000000001000100111100000000000000000000 +0000100111110101 0000010010000100111100000000000000000000 +0000100111111010 0001010000000100111100000000000000000000 +0000100111111111 0000100000000100111100000000000000000000 +0000100101100100 0000010011000100011000000000000000000000 +0000100101101000 0001010001000100011000000000000000000000 +0000100101101100 0000100001000100011000000000000000000000 +0000100101100001 0000010011000100011000000000000000000000 +0000100101101001 0001010010000100011000000000000000000000 +0000100101101101 0000110010000100011000000000000000000000 +0000100101100010 0001010001000100011000000000000000000000 +0000100101100110 0001010010000100011000000000000000000000 +0000100101101110 0001110000000100011000000000000000000000 +0000100101100011 0000100001000100011000000000000000000000 +0000100101100111 0000110010000100011000000000000000000000 +0000100101101011 0001110000000100011000000000000000000000 +0000100110100100 0000010011000100101000000000000000000000 +0000100110101000 0001010001000100101000000000000000000000 +0000100110101100 0000100001000100101000000000000000000000 +0000100110100001 0000010011000100101000000000000000000000 +0000100110101001 0001010010000100101000000000000000000000 +0000100110101101 0000110010000100101000000000000000000000 +0000100110100010 0001010001000100101000000000000000000000 +0000100110100110 0001010010000100101000000000000000000000 +0000100110101110 0001110000000100101000000000000000000000 +0000100110100011 0000100001000100101000000000000000000000 +0000100110100111 0000110010000100101000000000000000000000 +0000100110101011 0001110000000100101000000000000000000000 +0000100100100100 0000010011000100001000000000000000000000 +0000100100101000 0001010001000100001000000000000000000000 +0000100100101100 0000100001000100001000000000000000000000 +0000100100100001 0000010011000100001000000000000000000000 +0000100100101001 0001010010000100001000000000000000000000 +0000100100101101 0000110010000100001000000000000000000000 +0000100100100010 0001010001000100001000000000000000000000 +0000100100100110 0001010010000100001000000000000000000000 +0000100100101110 0001110000000100001000000000000000000000 +0000100100100011 0000100001000100001000000000000000000000 +0000100100100111 0000110010000100001000000000000000000000 +0000100100101011 0001110000000100001000000000000000000000 +0000100111100100 0000010011000100111000000000000000000000 +0000100111101000 0001010001000100111000000000000000000000 +0000100111101100 0000100001000100111000000000000000000000 +0000100111100001 0000010011000100111000000000000000000000 +0000100111101001 0001010010000100111000000000000000000000 +0000100111101101 0000110010000100111000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011100-------- 0000000000000000000000010000000010001000 +11000111-------- 0000000000000000000000000001000000000000 +0000100111100010 0001010001000100111000000000000000000000 +0000100111100110 0001010010000100111000000000000000000000 +0000100111101110 0001110000000100111000000000000000000000 +0000100111100011 0000100001000100111000000000000000000000 +0000100111100111 0000110010000100111000000000000000000000 +0000100111101011 0001110000000100111000000000000000000000 +0000100101010100 0000010011000100010100000000000000000000 +0000100101011000 0001010001000100010100000000000000000000 +0000100101011100 0000100001000100010100000000000000000000 +0000100101010001 0000010011000100010100000000000000000000 +0000100101011001 0001010010000100010100000000000000000000 +0000100101011101 0000110010000100010100000000000000000000 +0000100101010010 0001010001000100010100000000000000000000 +0000100101010110 0001010010000100010100000000000000000000 +0000100101011110 0001110000000100010100000000000000000000 +0000100101010011 0000100001000100010100000000000000000000 +0000100101010111 0000110010000100010100000000000000000000 +0000100101011011 0001110000000100010100000000000000000000 +0000100110010100 0000010011000100100100000000000000000000 +0000100110011000 0001010001000100100100000000000000000000 +0000100110011100 0000100001000100100100000000000000000000 +0000100110010001 0000010011000100100100000000000000000000 +0000100110011001 0001010010000100100100000000000000000000 +0000100110011101 0000110010000100100100000000000000000000 +0000100110010010 0001010001000100100100000000000000000000 +0000100110010110 0001010010000100100100000000000000000000 +0000100110011110 0001110000000100100100000000000000000000 +0000100110010011 0000100001000100100100000000000000000000 +0000100110010111 0000110010000100100100000000000000000000 +0000100110011011 0001110000000100100100000000000000000000 +0000100100010100 0000010011000100000100000000000000000000 +0000100100011000 0001010001000100000100000000000000000000 +0000100100011100 0000100001000100000100000000000000000000 +0000100100010001 0000010011000100000100000000000000000000 +0000100100011001 0001010010000100000100000000000000000000 +0000100100011101 0000110010000100000100000000000000000000 +0000100100010010 0001010001000100000100000000000000000000 +0000100100010110 0001010010000100000100000000000000000000 +0000100100011110 0001110000000100000100000000000000000000 +0000100100010011 0000100001000100000100000000000000000000 +0000100100010111 0000110010000100000100000000000000000000 +0000100100011011 0001110000000100000100000000000000000000 +0000100111010100 0000010011000100110100000000000000000000 +0000100111011000 0001010001000100110100000000000000000000 +0000100111011100 0000100001000100110100000000000000000000 +0000100111010001 0000010011000100110100000000000000000000 +0000100111011001 0001010010000100110100000000000000000000 +0000100111011101 0000110010000100110100000000000000000000 +0000100111010010 0001010001000100110100000000000000000000 +0000100111010110 0001010010000100110100000000000000000000 +0000100111011110 0001110000000100110100000000000000000000 +0000100111010011 0000100001000100110100000000000000000000 +0000100111010111 0000110010000100110100000000000000000000 +0000100111011011 0001110000000100110100000000000000000000 +0000100101000100 0000010011000100010000000000000000000000 +0000100101001000 0001010001000100010000000000000000000000 +0000100101001100 0000100001000100010000000000000000000000 +0000100101000001 0000010011000100010000000000000000000000 +0000100101001001 0001010010000100010000000000000000000000 +0000100101001101 0000110010000100010000000000000000000000 +0000100101000010 0001010001000100010000000000000000000000 +0000100101000110 0001010010000100010000000000000000000000 +0000100101001110 0001110000000100010000000000000000000000 +0000100101000011 0000100001000100010000000000000000000000 +0000100101000111 0000110010000100010000000000000000000000 +0000100101001011 0001110000000100010000000000000000000000 +0000100110000100 0000010011000100100000000000000000000000 +0000100110001000 0001010001000100100000000000000000000000 +0000100110001100 0000100001000100100000000000000000000000 +0000100110000001 0000010011000100100000000000000000000000 +0000100110001001 0001010010000100100000000000000000000000 +0000100110001101 0000110010000100100000000000000000000000 +0000100110000010 0001010001000100100000000000000000000000 +0000100110000110 0001010010000100100000000000000000000000 +0000100110001110 0001110000000100100000000000000000000000 +0000100110000011 0000100001000100100000000000000000000000 +0000100110000111 0000110010000100100000000000000000000000 +0000100110001011 0001110000000100100000000000000000000000 +0000100100000100 0000010011000100000000000000000000000000 +0000100100001000 0001010001000100000000000000000000000000 +0000100100001100 0000100001000100000000000000000000000000 +0000100100000001 0000010011000100000000000000000000000000 +0000100100001001 0001010010000100000000000000000000000000 +0000100100001101 0000110010000100000000000000000000000000 +0000100100000010 0001010001000100000000000000000000000000 +0000100100000110 0001010010000100000000000000000000000000 +0000100100001110 0001110000000100000000000000000000000000 +0000100100000011 0000100001000100000000000000000000000000 +0000100100000111 0000110010000100000000000000000000000000 +0000100100001011 0001110000000100000000000000000000000000 +0000100111000100 0000010011000100110000000000000000000000 +0000100111001000 0001010001000100110000000000000000000000 +0000100111001100 0000100001000100110000000000000000000000 +0000100111000001 0000010011000100110000000000000000000000 +0000100111001001 0001010010000100110000000000000000000000 +0000100111001101 0000110010000100110000000000000000000000 +0000100111000010 0001010001000100110000000000000000000000 +0000100111000110 0001010010000100110000000000000000000000 +0000100111001110 0001110000000100110000000000000000000000 +0000100111000011 0000100001000100110000000000000000000000 +0000100111000111 0000110010000100110000000000000000000000 +0000100111001011 0001110000000100110000000000000000000000 +0000100101110100 0000010011000100011100000000000000000000 +0000100101111000 0001010001000100011100000000000000000000 +0000100101111100 0000100001000100011100000000000000000000 +0000100101110001 0000010011000100011100000000000000000000 +0000100101111001 0001010010000100011100000000000000000000 +0000100101111101 0000110010000100011100000000000000000000 +0000100101110010 0001010001000100011100000000000000000000 +0000100101110110 0001010010000100011100000000000000000000 +0000100101111110 0001110000000100011100000000000000000000 +0000100101110011 0000100001000100011100000000000000000000 +0000100101110111 0000110010000100011100000000000000000000 +0000100101111011 0001110000000100011100000000000000000000 +0000100110110100 0000010011000100101100000000000000000000 +0000100110111000 0001010001000100101100000000000000000000 +0000100110111100 0000100001000100101100000000000000000000 +0000100110110001 0000010011000100101100000000000000000000 +0000100110111001 0001010010000100101100000000000000000000 +0000100110111101 0000110010000100101100000000000000000000 +0000100110110010 0001010001000100101100000000000000000000 +0000100110110110 0001010010000100101100000000000000000000 +0000100110111110 0001110000000100101100000000000000000000 +0000100110110011 0000100001000100101100000000000000000000 +0000100110110111 0000110010000100101100000000000000000000 +0000100110111011 0001110000000100101100000000000000000000 +0000100100110100 0000010011000100001100000000000000000000 +0000100100111000 0001010001000100001100000000000000000000 +0000100100111100 0000100001000100001100000000000000000000 +0000100100110001 0000010011000100001100000000000000000000 +0000100100111001 0001010010000100001100000000000000000000 +0000100100111101 0000110010000100001100000000000000000000 +0000100100110010 0001010001000100001100000000000000000000 +0000100100110110 0001010010000100001100000000000000000000 +0000100100111110 0001110000000100001100000000000000000000 +0000100100110011 0000100001000100001100000000000000000000 +0000100100110111 0000110010000100001100000000000000000000 +0000100100111011 0001110000000100001100000000000000000000 +0000100111110100 0000010011000100111100000000000000000000 +0000100111111000 0001010001000100111100000000000000000000 +0000100111111100 0000100001000100111100000000000000000000 +0000100111110001 0000010011000100111100000000000000000000 +0000100111111001 0001010010000100111100000000000000000000 +0000100111111101 0000110010000100111100000000000000000000 +0000100111110010 0001010001000100111100000000000000000000 +0000100111110110 0001010010000100111100000000000000000000 +0000100111111110 0001110000000100111100000000000000000000 +0000100111110011 0000100001000100111100000000000000000000 +0000100111110111 0000110010000100111100000000000000000000 +0000100111111011 0001110000000100111100000000000000000000 +0000110001100010 0001010000100000011000100000000000000000 +0000110010100010 0001010000100000101000100000000000000000 +0000110001010010 0000100000100000010100100000000000000000 +0000110010010010 0000100000100000100100100000000000000000 +0000110001000010 0001010000100000010000100000000000000000 +0000110010000010 0001010000100000100000100000000000000000 +0000110001110010 0000100000100000011100100000000000000000 +0000110010110010 0000100000100000101100100000000000000000 +0000101101101011 0001010000000000011000100000000000000000 +0000101110101011 0001010000000000101000100000000000000000 +0000101101011011 0000100000000000010100100000000000000000 +0000101110011011 0000100000000000100100100000000000000000 +0000101101001011 0001010000000000010000100000000000000000 +0000101110001011 0001010000000000100000100000000000000000 +0000101101111011 0000100000000000011100100000000000000000 +0000101110111011 0000100000000000101100100000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +01011011-------- 0000000000000000000000000000100010000000 +01011111-------- 0000000000000000000000000000010010000000 +01011100-------- 0000000000000000000000010000000010001000 +01011001-------- 0000000000000000000000000000100000000010 +01011101-------- 0000000000000000000000000000010000000010 +01011010-------- 0000000000000000000000000000100000000001 +01011110-------- 0000000000000000000000000000010000000001 +01001001-------- 0100000010000000000000000000001010001000 +0100100000100001 0100000010000000000000000000101001001000 +0100100000100010 0100000010000000000000000000101000101000 +0100100000100100 0100000010000000000000000000101000011000 +0100100001000001 0100000010000000000000000000011001001000 +0100100001000010 0100000010000000000000000000011000101000 +0100100001000100 0100000010000000000000000000011000011000 +0100100001100001 0100000010000000000000010000000001001000 +0100100001100010 0100000010000000000000010000000000101000 +0100100001100100 0100000010000000000000010000000000011000 +01001000000----- 0100000010000000000000000000000001010000 +01001011-------- 0101000000000000000000000000001010001000 +0100101000100001 0101000000000000000000000000101001001000 +0100101000100010 0101000000000000000000000000101000101000 +0100101000100100 0101000000000000000000000000101000011000 +0100101001000001 0101000000000000000000000000011001001000 +0100101001000010 0101000000000000000000000000011000101000 +0100101001000100 0101000000000000000000000000011000011000 +0100101001100001 0101000000000000000000010000000001001000 +0100101001100010 0101000000000000000000010000000000101000 +0100101001100100 0101000000000000000000010000000000011000 +01001010000----- 0101000000000000000000000000000001100000 +01000001-------- 1000000100000000000000000000001010000100 +0100000000100001 1000000100000000000000000000101001000100 +0100000000100010 1000000100000000000000000000101000100100 +0100000000100100 1000000100000000000000000000101000010100 +0100000001000001 1000000100000000000000000000011001000100 +0100000001000010 1000000100000000000000000000011000100100 +0100000001000100 1000000100000000000000000000011000010100 +0100000001100001 1000000100000000000000010000000001000100 +0100000001100010 1000000100000000000000010000000000100100 +0100000001100100 1000000100000000000000010000000000010100 +01000000000----- 1000000100000000000000000000000100000100 +01000011-------- 1010000000000000000000000000001010000100 +0100001000100001 1010000000000000000000000000101001000100 +0100001000100010 1010000000000000000000000000101000100100 +0100001000100100 1010000000000000000000000000101000010100 +0100001001000001 1010000000000000000000000000011001000100 +0100001001000010 1010000000000000000000000000011000100100 +0100001001000100 1010000000000000000000000000011000010100 +0100001001100001 1010000000000000000000010000000001000100 +0100001001100010 1010000000000000000000010000000000100100 +0100001001100100 1010000000000000000000010000000000010100 +01000010000----- 1010000000000000000000000000000100000100 +0100000010000000 1000000100000000000000001000000000000000 +0100001010000000 1010000000000000000000001000000000000000 +0100110000100001 0000000000000000000000001000101001001000 +0100110000100010 0000000000000000000000001000101000101000 +0100110000100100 0000000000000000000000001000101000011000 +0100110001000001 0000000000000000000000001000011001001000 +0100110001000010 0000000000000000000000001000011000101000 +0100110001000100 0000000000000000000000001000011000011000 +0100110001100001 0000000000000000000000011000000001001000 +0100110001100010 0000000000000000000000011000000000101000 +0100110001100100 0000000000000000000000011000000000011000 +0100100011000000 0100000010000000000000000000000000000000 +0100101011000000 0101000000000000000000000000000000000000 +0100110111000000 0000000000000000000000000000000000000000 +0100011001100001 0000000000000000000000010000000001000100 +0100011001100010 0000000000000000000000010000000000100100 +0100011001100100 0000000000000000000000010000000000010100 +0100011000100001 0000000000000000000000000000101001000100 +0100011000100010 0000000000000000000000000000101000100100 +0100011000100100 0000000000000000000000000000101000010100 +0100011001000001 0000000000000000000000000000011001000100 +0100011001000010 0000000000000000000000000000011000100100 +0100011001000100 0000000000000000000000000000011000010100 +01000110000----- 0000000000000000000000000000000100000100 +0100100010100000 0100000010000000000000000000000000000000 +0100101010100000 0101000000000000000000000000000000000000 +0100011100100001 0000000000000000000000000000101001000100 +0100011100100010 0000000000000000000000000000101000100100 +0100011100100100 0000000000000000000000000000101000010100 +0100011101000001 0000000000000000000000000000011001000100 +0100011101000010 0000000000000000000000000000011000100100 +0100011101000100 0000000000000000000000000000011000010100 +0100000011000000 1000000100000000000000000000000000000000 +0100001011000000 1010000000000000000000000000000000000000 +0100111001100001 0000000000000000000000010000000001001000 +0100111001100010 0000000000000000000000010000000000101000 +0100111001100100 0000000000000000000000010000000000011000 +0100111000100001 0000000000000000000000000000101001001000 +0100111000100010 0000000000000000000000000000101000101000 +0100111000100100 0000000000000000000000000000101000011000 +0100111001000001 0000000000000000000000000000011001001000 +0100111001000010 0000000000000000000000000000011000101000 +0100111001000100 0000000000000000000000000000011000011000 +01001110000----- 0000000000000000000000000000000000100000 +0100000010100000 1000000100000000000000000000000000000000 +0100001010100000 1010000000000000000000000000000000000000 +0100111100100001 0000000000000000000000000000101001001000 +0100111100100010 0000000000000000000000000000101000101000 +0100111100100100 0000000000000000000000000000101000011000 +0100111101000001 0000000000000000000000000000011001001000 +0100111101000010 0000000000000000000000000000011000101000 +0100111101000100 0000000000000000000000000000011000011000 +01011000001----- 0000000000000000000000000000100100001000 +01011000010----- 0000000000000000000000000000010100001000 +01011000100----- 0000000000000000000000000000110100001000 +01010000001----- 0000000000000000000000000000100100000100 +01010000010----- 0000000000000000000000000000010100000100 +01010000100----- 0000000000000000000000000000110100000100 +01011011-------- 0000000000000000000000000000100010000000 +01011111-------- 0000000000000000000000000000010010000000 +01011100-------- 0000000000000000000000010000000010001000 +01010101000----- 0000000000000000000000000000000000000000 +01010110000----- 0000000000000000000000000000000000000000 +01011001-------- 0000000000000000000000000000100000000010 +01011101-------- 0000000000000000000000000000010000000010 +01011010-------- 0000000000000000000000000000100000000001 +01011110-------- 0000000000000000000000000000010000000001 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +1001------------ 0000000000000011000000000000000000000000 +10001000-------- 0100000010000011000000000000101001001000 +10001010-------- 0100000010000011000000000000101000101000 +10001001-------- 0100000010000011000000000000011001001000 +10001011-------- 0100000010000011000000000000011000101000 +10001100-------- 0101000000000011000000000000101001001000 +10001110-------- 0101000000000011000000000000101000101000 +10001101-------- 0101000000000011000000000000011001001000 +10001111-------- 0101000000000011000000000000011000101000 +10000000-------- 1000000100000011000000000000101001000100 +10000010-------- 1000000100000011000000000000101000100100 +10000001-------- 1000000100000011000000000000011001000100 +10000011-------- 1000000100000011000000000000011000100100 +10000100-------- 1010000000000011000000000000101001000100 +10000110-------- 1010000000000011000000000000101000100100 +10000101-------- 1010000000000011000000000000011001000100 +10000111-------- 1010000000000011000000000000011000100100 +1011------------ 0000000000000010000000000000000000000000 +0010000000000000 0000000000000001000000000000000000000000 +1011------------ 0000000000000010000000000000000000000000 +1011------------ 0000000000000010000000000000000000000000 +1011------------ 0000000000000010000000000000000000000000 +1011------------ 0000000000000010000000000000000000000000 +1011------------ 0000000000000010000000000000000000000000 +10101000-------- 0100000010000010000000000000101001001000 +10101010-------- 0100000010000010000000000000101000101000 +10101001-------- 0100000010000010000000000000011001001000 +10101011-------- 0100000010000010000000000000011000101000 +10101100-------- 0101000000000010000000000000101001001000 +10101110-------- 0101000000000010000000000000101000101000 +10101101-------- 0101000000000010000000000000011001001000 +10101111-------- 0101000000000010000000000000011000101000 +10100000-------- 1000000100000010000000000000101001000100 +10100010-------- 1000000100000010000000000000101000100100 +10100001-------- 1000000100000010000000000000011001000100 +10100011-------- 1000000100000010000000000000011000100100 +10100100-------- 1010000000000010000000000000101001000100 +10100110-------- 1010000000000010000000000000101000100100 +10100101-------- 1010000000000010000000000000011001000100 +10100111-------- 1010000000000010000000000000011000100100 +11000001-------- 0000000000000000000000000000000000000000 +11000010-------- 0000000000000000000000000000000000000000 +11001001-------- 0000000000000000000000000000000000000000 +11001001-------- 0000000000000000000000000000000000000000 +11001001-------- 0000000000000000000000000000000000000000 +11001001-------- 0000000000000000000000000000000000000000 +11001001-------- 0000000000000000000000000000000000000000 +11001001-------- 0000000000000000000000000000000000000000 +11001001-------- 0000000000000000000000000000000000000000 +11001010-------- 0000000000000000000000000000000000000000 +11001100-------- 0000000000000000000000000000000000000000 +0001------------ ------1--------0------------------------ +0010------------ ------0--------1------------------------ +0011------------ ------1--------1------------------------ +011------------- ------0--------1------------------------ +111------------- ---------------------------------------- +1101------------ ---------------------------------------- +1100111--------- ---------------------------------------- +11001101-------- ---------------------------------------- +11001011-------- ---------------------------------------- +11001000-------- ---------------------------------------- +11000011-------- ---------------------------------------- +11000000-------- ---------------------------------------- +1100010--------- ---------------------------------------- +11000110-------- ---------------------------------------- +0100010--------- ---------------------------------------- +010001111------- ---------------------------------------- +01000111011----- ---------------------------------------- +010001110101---- ---------------------------------------- +0100011101001--- ---------------------------------------- +010001110100011- ---------------------------------------- +0100011101000101 ---------------------------------------- +0100011101000011 ---------------------------------------- +0100011101000000 ---------------------------------------- +01000111000----- ---------------------------------------- +010001110011---- ---------------------------------------- +0100011100101--- ---------------------------------------- +010001110010011- ---------------------------------------- +0100011100100101 ---------------------------------------- +0100011100100011 ---------------------------------------- +0100011100100000 ---------------------------------------- +010001101------- ---------------------------------------- +010001100011---- ---------------------------------------- +0100011000101--- ---------------------------------------- +010001100010011- ---------------------------------------- +0100011000100101 ---------------------------------------- +0100011000100011 ---------------------------------------- +0100011000100000 ---------------------------------------- +010001100101---- ---------------------------------------- +0100011001001--- ---------------------------------------- +010001100100011- ---------------------------------------- +0100011001000101 ---------------------------------------- +0100011001000011 ---------------------------------------- +0100011001000000 ---------------------------------------- +010001100111---- ---------------------------------------- +0100011001101--- ---------------------------------------- +010001100110011- ---------------------------------------- +0100011001100101 ---------------------------------------- +0100011001100011 ---------------------------------------- +0100011001100000 ---------------------------------------- +01000010111----- ---------------------------------------- +010000101101---- ---------------------------------------- +0100001011001--- ---------------------------------------- +01000010110001-- ---------------------------------------- +010000101100001- ---------------------------------------- +0100001011000001 ---------------------------------------- +010000101011---- ---------------------------------------- +0100001010101--- ---------------------------------------- +01000010101001-- ---------------------------------------- +010000101010001- ---------------------------------------- +0100001010100001 ---------------------------------------- +010000101001---- ---------------------------------------- +0100001010001--- ---------------------------------------- +01000010100001-- ---------------------------------------- +010000101000001- ---------------------------------------- +0100001010000001 ---------------------------------------- +010000100111---- ---------------------------------------- +0100001001101--- ---------------------------------------- +010000100110011- ---------------------------------------- +0100001001100101 ---------------------------------------- +0100001001100011 ---------------------------------------- +0100001001100000 ---------------------------------------- +010000100101---- ---------------------------------------- +0100001001001--- ---------------------------------------- +010000100100011- ---------------------------------------- +0100001001000101 ---------------------------------------- +0100001001000011 ---------------------------------------- +0100001001000000 ---------------------------------------- +010000100011---- ---------------------------------------- +0100001000101--- ---------------------------------------- +010000100010011- ---------------------------------------- +0100001000100101 ---------------------------------------- +0100001000100011 ---------------------------------------- +0100001000100000 ---------------------------------------- +01000000111----- ---------------------------------------- +010000001101---- ---------------------------------------- +0100000011001--- ---------------------------------------- +01000000110001-- ---------------------------------------- +010000001100001- ---------------------------------------- +0100000011000001 ---------------------------------------- +010000001011---- ---------------------------------------- +0100000010101--- ---------------------------------------- +01000000101001-- ---------------------------------------- +010000001010001- ---------------------------------------- +0100000010100001 ---------------------------------------- +010000001001---- ---------------------------------------- +0100000010001--- ---------------------------------------- +01000000100001-- ---------------------------------------- +010000001000001- ---------------------------------------- +0100000010000001 ---------------------------------------- +010000000111---- ---------------------------------------- +0100000001101--- ---------------------------------------- +010000000110011- ---------------------------------------- +0100000001100101 ---------------------------------------- +0100000001100011 ---------------------------------------- +0100000001100000 ---------------------------------------- +010000000101---- ---------------------------------------- +0100000001001--- ---------------------------------------- +010000000100011- ---------------------------------------- +0100000001000101 ---------------------------------------- +0100000001000011 ---------------------------------------- +0100000001000000 ---------------------------------------- +010000000011---- ---------------------------------------- +0100000000101--- ---------------------------------------- +010000000010011- ---------------------------------------- +0100000000100101 ---------------------------------------- +0100000000100011 ---------------------------------------- +0100000000100000 ---------------------------------------- +010011111------- ---------------------------------------- +01001111011----- ---------------------------------------- +010011110101---- ---------------------------------------- +0100111101001--- ---------------------------------------- +010011110100011- ---------------------------------------- +0100111101000101 ---------------------------------------- +0100111101000011 ---------------------------------------- +0100111101000000 ---------------------------------------- +01001111000----- ---------------------------------------- +010011110011---- ---------------------------------------- +0100111100101--- ---------------------------------------- +010011110010011- ---------------------------------------- +0100111100100101 ---------------------------------------- +0100111100100011 ---------------------------------------- +0100111100100000 ---------------------------------------- +010011101------- ---------------------------------------- +010011100011---- ---------------------------------------- +0100111000101--- ---------------------------------------- +010011100010011- ---------------------------------------- +0100111000100101 ---------------------------------------- +0100111000100011 ---------------------------------------- +0100111000100000 ---------------------------------------- +010011100101---- ---------------------------------------- +0100111001001--- ---------------------------------------- +010011100100011- ---------------------------------------- +0100111001000101 ---------------------------------------- +0100111001000011 ---------------------------------------- +0100111001000000 ---------------------------------------- +010011100111---- ---------------------------------------- +0100111001101--- ---------------------------------------- +010011100110011- ---------------------------------------- +0100111001100101 ---------------------------------------- +0100111001100011 ---------------------------------------- +0100111001100000 ---------------------------------------- +010011010------- ---------------------------------------- +0100110110------ ---------------------------------------- +01001101111----- ---------------------------------------- +010011011101---- ---------------------------------------- +0100110111001--- ---------------------------------------- +01001101110001-- ---------------------------------------- +010011011100001- ---------------------------------------- +0100110111000001 ---------------------------------------- +010011001------- ---------------------------------------- +010011000111---- ---------------------------------------- +0100110001101--- ---------------------------------------- +010011000110011- ---------------------------------------- +0100110001100101 ---------------------------------------- +0100110001100011 ---------------------------------------- +0100110001100000 ---------------------------------------- +010011000101---- ---------------------------------------- +0100110001001--- ---------------------------------------- +010011000100011- ---------------------------------------- +0100110001000101 ---------------------------------------- +0100110001000011 ---------------------------------------- +0100110001000000 ---------------------------------------- +01001100000----- ---------------------------------------- +010011000011---- ---------------------------------------- +0100110000101--- ---------------------------------------- +010011000010011- ---------------------------------------- +0100110000100101 ---------------------------------------- +0100110000100011 ---------------------------------------- +0100110000100000 ---------------------------------------- +01001010100----- ---------------------------------------- +010010101011---- ---------------------------------------- +0100101010101--- ---------------------------------------- +01001010101001-- ---------------------------------------- +010010101010001- ---------------------------------------- +0100101010100001 ---------------------------------------- +01001010111----- ---------------------------------------- +010010101101---- ---------------------------------------- +0100101011001--- ---------------------------------------- +01001010110001-- ---------------------------------------- +010010101100001- ---------------------------------------- +0100101011000001 ---------------------------------------- +010010100111---- ---------------------------------------- +0100101001101--- ---------------------------------------- +010010100110011- ---------------------------------------- +0100101001100101 ---------------------------------------- +0100101001100011 ---------------------------------------- +0100101001100000 ---------------------------------------- +010010100101---- ---------------------------------------- +0100101001001--- ---------------------------------------- +010010100100011- ---------------------------------------- +0100101001000101 ---------------------------------------- +0100101001000011 ---------------------------------------- +0100101001000000 ---------------------------------------- +010010100011---- ---------------------------------------- +0100101000101--- ---------------------------------------- +010010100010011- ---------------------------------------- +0100101000100101 ---------------------------------------- +0100101000100011 ---------------------------------------- +0100101000100000 ---------------------------------------- +01001000100----- ---------------------------------------- +010010001011---- ---------------------------------------- +0100100010101--- ---------------------------------------- +01001000101001-- ---------------------------------------- +010010001010001- ---------------------------------------- +0100100010100001 ---------------------------------------- +01001000111----- ---------------------------------------- +010010001101---- ---------------------------------------- +0100100011001--- ---------------------------------------- +01001000110001-- ---------------------------------------- +010010001100001- ---------------------------------------- +0100100011000001 ---------------------------------------- +010010000111---- ---------------------------------------- +0100100001101--- ---------------------------------------- +010010000110011- ---------------------------------------- +0100100001100101 ---------------------------------------- +0100100001100011 ---------------------------------------- +0100100001100000 ---------------------------------------- +010010000101---- ---------------------------------------- +0100100001001--- ---------------------------------------- +010010000100011- ---------------------------------------- +0100100001000101 ---------------------------------------- +0100100001000011 ---------------------------------------- +0100100001000000 ---------------------------------------- +010010000011---- ---------------------------------------- +0100100000101--- ---------------------------------------- +010010000010011- ---------------------------------------- +0100100000100101 ---------------------------------------- +0100100000100011 ---------------------------------------- +0100100000100000 ---------------------------------------- +01010111-------- ---------------------------------------- +010101101------- ---------------------------------------- +0101011001------ ---------------------------------------- +01010110001----- ---------------------------------------- +01010100-------- ---------------------------------------- +010101011------- ---------------------------------------- +0101010101------ ---------------------------------------- +01010101001----- ---------------------------------------- +0101001--------- ---------------------------------------- +01010001-------- ---------------------------------------- +0101000011------ ---------------------------------------- +01010000101----- ---------------------------------------- +01010000011----- ---------------------------------------- +01010000000----- ---------------------------------------- +0101100011------ ---------------------------------------- +01011000101----- ---------------------------------------- +01011000011----- ---------------------------------------- +01011000000----- ---------------------------------------- +0000110011------ ---------------------------------------- +0000110010001--- ---------------------------------------- +00001100100001-- ---------------------------------------- +000011001000000- ---------------------------------------- +0000110010000011 ---------------------------------------- +0000110010011--- ---------------------------------------- +00001100100101-- ---------------------------------------- +000011001001000- ---------------------------------------- +0000110010010011 ---------------------------------------- +0000110010111--- ---------------------------------------- +00001100101101-- ---------------------------------------- +000011001011000- ---------------------------------------- +0000110010110011 ---------------------------------------- +0000110010101--- ---------------------------------------- +00001100101001-- ---------------------------------------- +000011001010000- ---------------------------------------- +0000110010100011 ---------------------------------------- +0000110000------ ---------------------------------------- +0000110001001--- ---------------------------------------- +00001100010001-- ---------------------------------------- +000011000100000- ---------------------------------------- +0000110001000011 ---------------------------------------- +0000110001011--- ---------------------------------------- +00001100010101-- ---------------------------------------- +000011000101000- ---------------------------------------- +0000110001010011 ---------------------------------------- +0000110001111--- ---------------------------------------- +00001100011101-- ---------------------------------------- +000011000111000- ---------------------------------------- +0000110001110011 ---------------------------------------- +0000110001101--- ---------------------------------------- +00001100011001-- ---------------------------------------- +000011000110000- ---------------------------------------- +0000110001100011 ---------------------------------------- +000011101100---- ---------------------------------------- +0000111011010--- ---------------------------------------- +00001110110110-- ---------------------------------------- +000011101101110- ---------------------------------------- +0000111011011110 ---------------------------------------- +000011101111---- ---------------------------------------- +0000111011100--- ---------------------------------------- +00001110111011-- ---------------------------------------- +000011101110100- ---------------------------------------- +0000111011101011 ---------------------------------------- +000011101000---- ---------------------------------------- +000011101001010- ---------------------------------------- +0000111010010110 ---------------------------------------- +000011101001000- ---------------------------------------- +0000111010010010 ---------------------------------------- +000011101001100- ---------------------------------------- +0000111010011010 ---------------------------------------- +000011101011---- ---------------------------------------- +000011101010010- ---------------------------------------- +0000111010100111 ---------------------------------------- +000011101010000- ---------------------------------------- +0000111010100011 ---------------------------------------- +000011101010110- ---------------------------------------- +0000111010101111 ---------------------------------------- +000011100000---- ---------------------------------------- +0000111000010--- ---------------------------------------- +00001110000110-- ---------------------------------------- +000011100001110- ---------------------------------------- +0000111000011110 ---------------------------------------- +000011100011---- ---------------------------------------- +0000111000100--- ---------------------------------------- +00001110001011-- ---------------------------------------- +000011100010100- ---------------------------------------- +0000111000101011 ---------------------------------------- +000011100100---- ---------------------------------------- +000011100101010- ---------------------------------------- +0000111001010110 ---------------------------------------- +000011100101000- ---------------------------------------- +0000111001010010 ---------------------------------------- +000011100101100- ---------------------------------------- +0000111001011010 ---------------------------------------- +000011100111---- ---------------------------------------- +000011100110010- ---------------------------------------- +0000111001100111 ---------------------------------------- +000011100110000- ---------------------------------------- +0000111001100011 ---------------------------------------- +000011100110110- ---------------------------------------- +0000111001101111 ---------------------------------------- +00001010-------- ---------------------------------------- +0000101111------ ---------------------------------------- +0000101110000--- ---------------------------------------- +00001011100011-- ---------------------------------------- +000010111000100- ---------------------------------------- +0000101110001010 ---------------------------------------- +0000101110010--- ---------------------------------------- +00001011100111-- ---------------------------------------- +000010111001100- ---------------------------------------- +0000101110011010 ---------------------------------------- +0000101110110--- ---------------------------------------- +00001011101111-- ---------------------------------------- +000010111011100- ---------------------------------------- +0000101110111010 ---------------------------------------- +0000101110100--- ---------------------------------------- +00001011101011-- ---------------------------------------- +000010111010100- ---------------------------------------- +0000101110101010 ---------------------------------------- +0000101100------ ---------------------------------------- +0000101101000--- ---------------------------------------- +00001011010011-- ---------------------------------------- +000010110100100- ---------------------------------------- +0000101101001010 ---------------------------------------- +0000101101010--- ---------------------------------------- +00001011010111-- ---------------------------------------- +000010110101100- ---------------------------------------- +0000101101011010 ---------------------------------------- +0000101101110--- ---------------------------------------- +00001011011111-- ---------------------------------------- +000010110111100- ---------------------------------------- +0000101101111010 ---------------------------------------- +0000101101100--- ---------------------------------------- +00001011011011-- ---------------------------------------- +000010110110100- ---------------------------------------- +0000101101101010 ---------------------------------------- +0000011--------- ---------------------------------------- +0000010111------ ---------------------------------------- +0000010100------ ---------------------------------------- +0000001111------ ---------------------------------------- +00000011101----- ---------------------------------------- +000000111001---- ---------------------------------------- +000000110000---- ---------------------------------------- +000000110011---- ---------------------------------------- +00000011011----- ---------------------------------------- +000000110101---- ---------------------------------------- +00000001-------- ---------------------------------------- +000000001------- ---------------------------------------- +0000000001------ ---------------------------------------- +00000000001----- ---------------------------------------- +000000000001---- ---------------------------------------- +0000000000001--- ---------------------------------------- +00000000000001-- ---------------------------------------- +000000000000001- ---------------------------------------- +0000000000000001 ---------------------------------------- diff --git a/benchmarks/benchmarks/espresso/main.c b/benchmarks/benchmarks/espresso/main.c new file mode 100644 index 0000000..fe1829d --- /dev/null +++ b/benchmarks/benchmarks/espresso/main.c @@ -0,0 +1,755 @@ +/* + * Main driver for espresso + * + * Old style -do xxx, -out xxx, etc. are still supported. + */ + +#include "espresso.h" +#include "main.h" /* table definitions for options */ + +static FILE *last_fp; +static int input_type = FD_type; + +#include + +void gmalloc_exit(void); + +static int mainx(int argc, char* argv[]); + +int main(int argc, char* argv[]) { + int i; + extern int optind; + for(i = 0; i < 20; i++) { // benchmark N iterations + optind = 0; + mainx(argc,argv); + } +} + +static int mainx(int argc, char *argv[]) +{ + int i, j, first, last, strategy, out_type, option; + pPLA PLA, PLA1; + pcover F, Fold, Dold; + pset last1, p; + cost_t cost; + bool error, exact_cover; + long start; + extern char *optarg; + extern int optind; + +#ifdef BWGC + { + extern gc_init(); + gc_init(); + } +#endif + + start = ptime(); + + error = FALSE; + init_runtime(); +#ifdef RANDOM + srandom(314973); +#endif + + option = 0; /* default -D: ESPRESSO */ + out_type = F_type; /* default -o: default is ON-set only */ + debug = 0; /* default -d: no debugging info */ + verbose_debug = FALSE; /* default -v: not verbose */ + print_solution = FALSE; /* default -x: print the solution (!) */ + summary = FALSE; /* default -s: no summary */ + trace = FALSE; /* default -t: no trace information */ + strategy = 0; /* default -S: strategy number */ + first = -1; /* default -R: select range */ + last = -1; + remove_essential = TRUE; /* default -e: */ + force_irredundant = TRUE; + unwrap_onset = TRUE; + single_expand = FALSE; + pos = FALSE; + recompute_onset = FALSE; + use_super_gasp = FALSE; + use_random_order = FALSE; + kiss = FALSE; + echo_comments = TRUE; + echo_unknown_commands = TRUE; + exact_cover = FALSE; /* for -qm option, the default */ + + backward_compatibility_hack(&argc, argv, &option, &out_type); + + + /* parse command line options*/ + while ((i = getopt(argc, argv, "D:S:de:o:r:stv:x")) != EOF) { + switch(i) { + case 'D': /* -Dcommand invokes a subcommand */ + for(j = 0; option_table[j].name != 0; j++) { + if (strcmp(optarg, option_table[j].name) == 0) { + option = j; + break; + } + } + if (option_table[j].name == 0) { + fprintf(stderr, "%s: bad subcommand \"%s\"\n", + argv[0], optarg); + exit(1); + } + break; + + case 'o': /* -ooutput selects and output option */ + for(j = 0; pla_types[j].key != 0; j++) { + if (strcmp(optarg, pla_types[j].key+1) == 0) { + out_type = pla_types[j].value; + break; + } + } + if (pla_types[j].key == 0) { + fprintf(stderr, "%s: bad output type \"%s\"\n", + argv[0], optarg); + exit(1); + } + break; + + case 'e': /* -eespresso selects an option for espresso */ + for(j = 0; esp_opt_table[j].name != 0; j++) { + if (strcmp(optarg, esp_opt_table[j].name) == 0) { + *(esp_opt_table[j].variable) = esp_opt_table[j].value; + break; + } + } + if (esp_opt_table[j].name == 0) { + fprintf(stderr, "%s: bad espresso option \"%s\"\n", + argv[0], optarg); + exit(1); + } + break; + + case 'd': /* -d turns on (softly) all debug switches */ + debug = debug_table[0].value; + trace = TRUE; + summary = TRUE; + break; + + case 'v': /* -vdebug invokes a debug option */ + verbose_debug = TRUE; + for(j = 0; debug_table[j].name != 0; j++) { + if (strcmp(optarg, debug_table[j].name) == 0) { + debug |= debug_table[j].value; + break; + } + } + if (debug_table[j].name == 0) { + fprintf(stderr, "%s: bad debug type \"%s\"\n", + argv[0], optarg); + exit(1); + } + break; + + case 't': + trace = TRUE; + break; + + case 's': + summary = TRUE; + break; + + case 'x': /* -x suppress printing of results */ + print_solution = FALSE; + break; + + case 'S': /* -S sets a strategy for several cmds */ + strategy = atoi(optarg); + break; + + case 'r': /* -r selects range (outputs or vars) */ + if (sscanf(optarg, "%d-%d", &first, &last) < 2) { + fprintf(stderr, "%s: bad output range \"%s\"\n", + argv[0], optarg); + exit(1); + } + break; + + default: + usage(); + exit(1); + } + } + + /* provide version information and summaries */ + if (summary || trace) { + /* echo command line and arguments */ + printf("#"); + for(i = 0; i < argc; i++) { + printf(" %s", argv[i]); + } + printf("\n"); + printf("# %s\n", VERSION); + } + + /* the remaining arguments are argv[optind ... argc-1] */ + PLA = PLA1 = NIL(PLA_t); + switch(option_table[option].num_plas) { + case 2: + if (optind+2 < argc) fatal("trailing arguments on command line"); + getPLA(optind++, argc, argv, option, &PLA, out_type); + getPLA(optind++, argc, argv, option, &PLA1, out_type); + break; + case 1: + if (optind+1 < argc) fatal("trailing arguments on command line"); + getPLA(optind++, argc, argv, option, &PLA, out_type); + break; + } + if (optind < argc) fatal("trailing arguments on command line"); + + if (summary || trace) { + if (PLA != NIL(PLA_t)) PLA_summary(PLA); + if (PLA1 != NIL(PLA_t)) PLA_summary(PLA1); + } + +/* + * Now a case-statement to decide what to do + */ + + switch(option_table[option].key) { + + +/******************** Espresso operations ********************/ + + case KEY_ESPRESSO: + Fold = sf_save(PLA->F); + PLA->F = espresso(PLA->F, PLA->D, PLA->R); + EXECUTE(error=verify(PLA->F,Fold,PLA->D), VERIFY_TIME, PLA->F, cost); + if (error) { + print_solution = FALSE; + PLA->F = Fold; + (void) check_consistency(PLA); + } else { + free_cover(Fold); + } + break; + + case KEY_MANY_ESPRESSO: { + int pla_type; + do { + EXEC(PLA->F=espresso(PLA->F,PLA->D,PLA->R),"ESPRESSO ",PLA->F); + if (print_solution) { + fprint_pla(stdout, PLA, out_type); + (void) fflush(stdout); + } + pla_type = PLA->pla_type; + free_PLA(PLA); + setdown_cube(); + FREE(cube.part_size); + } while (read_pla(last_fp, TRUE, TRUE, pla_type, &PLA) != EOF); + exit(0); + } + + case KEY_simplify: + EXEC(PLA->F = simplify(cube1list(PLA->F)), "SIMPLIFY ", PLA->F); + break; + + case KEY_so: /* minimize all functions as single-output */ + if (strategy < 0 || strategy > 1) { + strategy = 0; + } + so_espresso(PLA, strategy); + break; + + case KEY_so_both: /* minimize all functions as single-output */ + if (strategy < 0 || strategy > 1) { + strategy = 0; + } + so_both_espresso(PLA, strategy); + break; + + case KEY_expand: /* execute expand */ + EXECUTE(PLA->F=expand(PLA->F,PLA->R,FALSE),EXPAND_TIME, PLA->F, cost); + break; + + case KEY_irred: /* extract minimal irredundant subset */ + EXECUTE(PLA->F = irredundant(PLA->F, PLA->D), IRRED_TIME, PLA->F, cost); + break; + + case KEY_reduce: /* perform reduction */ + EXECUTE(PLA->F = reduce(PLA->F, PLA->D), REDUCE_TIME, PLA->F, cost); + break; + + case KEY_essen: /* check for essential primes */ + foreach_set(PLA->F, last1, p) { + SET(p, RELESSEN); + RESET(p, NONESSEN); + } + EXECUTE(F = essential(&(PLA->F), &(PLA->D)), ESSEN_TIME, PLA->F, cost); + free_cover(F); + break; + + case KEY_super_gasp: + PLA->F = super_gasp(PLA->F, PLA->D, PLA->R, &cost); + break; + + case KEY_gasp: + PLA->F = last_gasp(PLA->F, PLA->D, PLA->R, &cost); + break; + + case KEY_make_sparse: /* make_sparse step of Espresso */ + PLA->F = make_sparse(PLA->F, PLA->D, PLA->R); + break; + + case KEY_exact: + exact_cover = TRUE; + + case KEY_qm: + Fold = sf_save(PLA->F); + PLA->F = minimize_exact(PLA->F, PLA->D, PLA->R, exact_cover); + EXECUTE(error=verify(PLA->F,Fold,PLA->D), VERIFY_TIME, PLA->F, cost); + if (error) { + print_solution = FALSE; + PLA->F = Fold; + (void) check_consistency(PLA); + } + free_cover(Fold); + break; + + case KEY_primes: /* generate all prime implicants */ + EXEC(PLA->F = primes_consensus(cube2list(PLA->F, PLA->D)), + "PRIMES ", PLA->F); + break; + + case KEY_map: /* print out a Karnaugh map of function */ + map(PLA->F); + print_solution = FALSE; + break; + + + +/******************** Output phase and bit pairing ********************/ + + case KEY_opo: /* sasao output phase assignment */ + phase_assignment(PLA, strategy); + break; + + case KEY_opoall: /* try all phase assignments (!) */ + if (first < 0 || first >= cube.part_size[cube.output]) { + first = 0; + } + if (last < 0 || last >= cube.part_size[cube.output]) { + last = cube.part_size[cube.output] - 1; + } + opoall(PLA, first, last, strategy); + break; + + case KEY_pair: /* find an optimal pairing */ + find_optimal_pairing(PLA, strategy); + break; + + case KEY_pairall: /* try all pairings !! */ + pair_all(PLA, strategy); + break; + + + +/******************** Simple cover operations ********************/ + + case KEY_echo: /* echo the PLA */ + break; + + case KEY_taut: /* tautology check */ + printf("ON-set is%sa tautology\n", + tautology(cube1list(PLA->F)) ? " " : " not "); + print_solution = FALSE; + break; + + case KEY_contain: /* single cube containment */ + PLA->F = sf_contain(PLA->F); + break; + + case KEY_intersect: /* cover intersection */ + PLA->F = cv_intersect(PLA->F, PLA1->F); + break; + + case KEY_union: /* cover union */ + PLA->F = sf_union(PLA->F, PLA1->F); + break; + + case KEY_disjoint: /* make cover disjoint */ + PLA->F = make_disjoint(PLA->F); + break; + + case KEY_dsharp: /* cover disjoint-sharp */ + PLA->F = cv_dsharp(PLA->F, PLA1->F); + break; + + case KEY_sharp: /* cover sharp */ + PLA->F = cv_sharp(PLA->F, PLA1->F); + break; + + case KEY_lexsort: /* lexical sort order */ + PLA->F = lex_sort(PLA->F); + break; + + case KEY_stats: /* print info on size */ + if (! summary) PLA_summary(PLA); + print_solution = FALSE; + break; + + case KEY_minterms: /* explode into minterms */ + if (first < 0 || first >= cube.num_vars) { + first = 0; + } + if (last < 0 || last >= cube.num_vars) { + last = cube.num_vars - 1; + } + PLA->F = sf_dupl(unravel_range(PLA->F, first, last)); + break; + + case KEY_d1merge: /* distance-1 merge */ + if (first < 0 || first >= cube.num_vars) { + first = 0; + } + if (last < 0 || last >= cube.num_vars) { + last = cube.num_vars - 1; + } + for(i = first; i <= last; i++) { + PLA->F = d1merge(PLA->F, i); + } + break; + + case KEY_d1merge_in: /* distance-1 merge inputs only */ + for(i = 0; i < cube.num_binary_vars; i++) { + PLA->F = d1merge(PLA->F, i); + } + break; + + case KEY_PLA_verify: /* check two PLAs for equivalence */ + EXECUTE(error = PLA_verify(PLA, PLA1), VERIFY_TIME, PLA->F, cost); + if (error) { + printf("PLA comparison failed; the PLA's are not equivalent\n"); + exit(1); + } else { + printf("PLA's compared equal\n"); + exit(0); + } + break; /* silly */ + + case KEY_verify: /* check two covers for equivalence */ + Fold = PLA->F; Dold = PLA->D; F = PLA1->F; + EXECUTE(error=verify(F, Fold, Dold), VERIFY_TIME, PLA->F, cost); + if (error) { + printf("PLA comparison failed; the PLA's are not equivalent\n"); + exit(1); + } else { + printf("PLA's compared equal\n"); + exit(0); + } + break; /* silly */ + + case KEY_check: /* check consistency */ + (void) check_consistency(PLA); + print_solution = FALSE; + break; + + case KEY_mapdc: /* compute don't care set */ + map_dcset(PLA); + out_type = FD_type; + break; + + case KEY_equiv: + find_equiv_outputs(PLA); + print_solution = FALSE; + break; + + case KEY_separate: /* remove PLA->D from PLA->F */ + PLA->F = complement(cube2list(PLA->D, PLA->R)); + break; + + case KEY_xor: { + pcover T1 = cv_intersect(PLA->F, PLA1->R); + pcover T2 = cv_intersect(PLA1->F, PLA->R); + free_cover(PLA->F); + PLA->F = sf_contain(sf_join(T1, T2)); + free_cover(T1); + free_cover(T2); + break; + } + + case KEY_fsm: { + disassemble_fsm(PLA, summary); + print_solution = FALSE; + break; + } + + case KEY_test: { + pcover T, E; + T = sf_join(PLA->D, PLA->R); + E = new_cover(10); + sf_free(PLA->F); + EXECUTE(PLA->F = complement(cube1list(T)), COMPL_TIME, PLA->F, cost); + EXECUTE(PLA->F = expand(PLA->F, T, FALSE), EXPAND_TIME, PLA->F, cost); + EXECUTE(PLA->F = irredundant(PLA->F, E), IRRED_TIME, PLA->F, cost); + sf_free(T); + T = sf_join(PLA->F, PLA->R); + EXECUTE(PLA->D = expand(PLA->D, T, FALSE), EXPAND_TIME, PLA->D, cost); + EXECUTE(PLA->D = irredundant(PLA->D, E), IRRED_TIME, PLA->D, cost); + sf_free(T); + sf_free(E); + break; + } + + + } + + /* Print a runtime summary if trace mode enabled */ + if (trace) { + runtime(); + } + + /* Print total runtime */ + if (summary || trace) { + print_trace(PLA->F, option_table[option].name, ptime()-start); + } + + /* Output the solution */ + if (print_solution) { + EXECUTE(fprint_pla(stdout, PLA, out_type), WRITE_TIME, PLA->F, cost); + } + + /* Crash and burn if there was a verify error */ + if (error) { + fatal("cover verification failed"); + } + + /* cleanup all used memory */ + free_PLA(PLA); + FREE(cube.part_size); + setdown_cube(); /* free the cube/cdata structure data */ + sf_cleanup(); /* free unused set structures */ + sm_cleanup(); /* sparse matrix cleanup */ + return 0; +} + + +getPLA(opt, argc, argv, option, PLA, out_type) +int opt; +int argc; +char *argv[]; +int option; +pPLA *PLA; +int out_type; +{ + FILE *fp; + int needs_dcset, needs_offset; + char *fname; + + if (opt >= argc) { + fp = stdin; + fname = "(stdin)"; + } else { + fname = argv[opt]; + if (strcmp(fname, "-") == 0) { + fp = stdin; + } else if ((fp = fopen(argv[opt], "r")) == NULL) { + fprintf(stderr, "%s: Unable to open %s\n", argv[0], fname); + exit(1); + } + } + if (option_table[option].key == KEY_echo) { + needs_dcset = (out_type & D_type) != 0; + needs_offset = (out_type & R_type) != 0; + } else { + needs_dcset = option_table[option].needs_dcset; + needs_offset = option_table[option].needs_offset; + } + + if (read_pla(fp, needs_dcset, needs_offset, input_type, PLA) == EOF) { + fprintf(stderr, "%s: Unable to find PLA on file %s\n", argv[0], fname); + exit(1); + } + (*PLA)->filename = util_strsav(fname); + filename = (*PLA)->filename; +/* (void) fclose(fp);*/ +/* hackto support -Dmany */ + last_fp = fp; +} + + +runtime() +{ + int i; + long total = 1, temp; + + for(i = 0; i < TIME_COUNT; i++) { + total += total_time[i]; + } + for(i = 0; i < TIME_COUNT; i++) { + if (total_calls[i] != 0) { + temp = 100 * total_time[i]; + printf("# %s\t%2d call(s) for %s (%2ld.%01ld%%)\n", + total_name[i], total_calls[i], print_time(total_time[i]), + temp/total, (10 * (temp%total)) / total); + } + } +} + + +init_runtime() +{ + total_name[READ_TIME] = "READ "; + total_name[WRITE_TIME] = "WRITE "; + total_name[COMPL_TIME] = "COMPL "; + total_name[REDUCE_TIME] = "REDUCE "; + total_name[EXPAND_TIME] = "EXPAND "; + total_name[ESSEN_TIME] = "ESSEN "; + total_name[IRRED_TIME] = "IRRED "; + total_name[GREDUCE_TIME] = "REDUCE_GASP"; + total_name[GEXPAND_TIME] = "EXPAND_GASP"; + total_name[GIRRED_TIME] = "IRRED_GASP "; + total_name[MV_REDUCE_TIME] ="MV_REDUCE "; + total_name[RAISE_IN_TIME] = "RAISE_IN "; + total_name[VERIFY_TIME] = "VERIFY "; + total_name[PRIMES_TIME] = "PRIMES "; + total_name[MINCOV_TIME] = "MINCOV "; +} + + +subcommands() +{ + int i, col; + printf(" "); + col = 16; + for(i = 0; option_table[i].name != 0; i++) { + if ((col + strlen(option_table[i].name) + 1) > 76) { + printf(",\n "); + col = 16; + } else if (i != 0) { + printf(", "); + } + printf("%s", option_table[i].name); + col += strlen(option_table[i].name) + 2; + } + printf("\n"); +} + + +usage() +{ + printf("%s\n\n", VERSION); + printf("SYNOPSIS: espresso [options] [file]\n\n"); + printf(" -d Enable debugging\n"); + printf(" -e[opt] Select espresso option:\n"); + printf(" fast, ness, nirr, nunwrap, onset, pos, strong,\n"); + printf(" eat, eatdots, kiss, random\n"); + printf(" -o[type] Select output format:\n"); + printf(" f, fd, fr, fdr, pleasure, eqntott, kiss, cons\n"); + printf(" -rn-m Select range for subcommands:\n"); + printf(" d1merge: first and last variables (0 ... m-1)\n"); + printf(" minterms: first and last variables (0 ... m-1)\n"); + printf(" opoall: first and last outputs (0 ... m-1)\n"); + printf(" -s Provide short execution summary\n"); + printf(" -t Provide longer execution trace\n"); + printf(" -x Suppress printing of solution\n"); + printf(" -v[type] Verbose debugging detail (-v '' for all)\n"); + printf(" -D[cmd] Execute subcommand 'cmd':\n"); + subcommands(); + printf(" -Sn Select strategy for subcommands:\n"); + printf(" opo: bit2=exact bit1=repeated bit0=skip sparse\n"); + printf(" opoall: 0=minimize, 1=exact\n"); + printf(" pair: 0=algebraic, 1=strongd, 2=espresso, 3=exact\n"); + printf(" pairall: 0=minimize, 1=exact, 2=opo\n"); + printf(" so_espresso: 0=minimize, 1=exact\n"); + printf(" so_both: 0=minimize, 1=exact\n"); +} + +/* + * Hack for backward compatibility (ACK! ) + */ + +backward_compatibility_hack(argc, argv, option, out_type) +int *argc; +char **argv; +int *option; +int *out_type; +{ + int i, j; + + /* Scan the argument list for something to do (default is ESPRESSO) */ + *option = 0; + for(i = 1; i < (*argc)-1; i++) { + if (strcmp(argv[i], "-do") == 0) { + for(j = 0; option_table[j].name != 0; j++) + if (strcmp(argv[i+1], option_table[j].name) == 0) { + *option = j; + delete_arg(argc, argv, i+1); + delete_arg(argc, argv, i); + break; + } + if (option_table[j].name == 0) { + fprintf(stderr, + "espresso: bad keyword \"%s\" following -do\n",argv[i+1]); + exit(1); + } + break; + } + } + + for(i = 1; i < (*argc)-1; i++) { + if (strcmp(argv[i], "-out") == 0) { + for(j = 0; pla_types[j].key != 0; j++) + if (strcmp(pla_types[j].key+1, argv[i+1]) == 0) { + *out_type = pla_types[j].value; + delete_arg(argc, argv, i+1); + delete_arg(argc, argv, i); + break; + } + if (pla_types[j].key == 0) { + fprintf(stderr, + "espresso: bad keyword \"%s\" following -out\n",argv[i+1]); + exit(1); + } + break; + } + } + + for(i = 1; i < (*argc); i++) { + if (argv[i][0] == '-') { + for(j = 0; esp_opt_table[j].name != 0; j++) { + if (strcmp(argv[i]+1, esp_opt_table[j].name) == 0) { + delete_arg(argc, argv, i); + *(esp_opt_table[j].variable) = esp_opt_table[j].value; + break; + } + } + } + } + + if (check_arg(argc, argv, "-fdr")) input_type = FDR_type; + if (check_arg(argc, argv, "-fr")) input_type = FR_type; + if (check_arg(argc, argv, "-f")) input_type = F_type; +} + + +/* delete_arg -- delete an argument from the argument list */ +delete_arg(argc, argv, num) +int *argc, num; +register char *argv[]; +{ + register int i; + (*argc)--; + for(i = num; i < *argc; i++) { + argv[i] = argv[i+1]; + } +} + + +/* check_arg -- scan argv for an argument, and return TRUE if found */ +bool check_arg(argc, argv, s) +int *argc; +register char *argv[], *s; +{ + register int i; + for(i = 1; i < *argc; i++) { + if (strcmp(argv[i], s) == 0) { + delete_arg(argc, argv, i); + return TRUE; + } + } + return FALSE; +} diff --git a/benchmarks/benchmarks/espresso/main.h b/benchmarks/benchmarks/espresso/main.h new file mode 100644 index 0000000..216ce3a --- /dev/null +++ b/benchmarks/benchmarks/espresso/main.h @@ -0,0 +1,113 @@ +enum keys { + KEY_ESPRESSO, KEY_PLA_verify, KEY_check, KEY_contain, KEY_d1merge, + KEY_disjoint, KEY_dsharp, KEY_echo, KEY_essen, KEY_exact, KEY_expand, + KEY_gasp, KEY_intersect, KEY_irred, KEY_lexsort, KEY_make_sparse, + KEY_map, KEY_mapdc, KEY_minterms, KEY_opo, KEY_opoall, + KEY_pair, KEY_pairall, KEY_primes, KEY_qm, KEY_reduce, KEY_sharp, + KEY_simplify, KEY_so, KEY_so_both, KEY_stats, KEY_super_gasp, KEY_taut, + KEY_test, KEY_equiv, KEY_union, KEY_verify, KEY_MANY_ESPRESSO, + KEY_separate, KEY_xor, KEY_d1merge_in, KEY_fsm, + KEY_unknown +}; + +/* Lookup table for program options */ +struct { + char *name; + enum keys key; + int num_plas; + bool needs_offset; + bool needs_dcset; +} option_table [] = { + /* ways to minimize functions */ + "ESPRESSO", KEY_ESPRESSO, 1, TRUE, TRUE, /* must be first */ + "many", KEY_MANY_ESPRESSO, 1, TRUE, TRUE, + "exact", KEY_exact, 1, TRUE, TRUE, + "qm", KEY_qm, 1, TRUE, TRUE, + "single_output", KEY_so, 1, TRUE, TRUE, + "so", KEY_so, 1, TRUE, TRUE, + "so_both", KEY_so_both, 1, TRUE, TRUE, + "simplify", KEY_simplify, 1, FALSE, FALSE, + "echo", KEY_echo, 1, FALSE, FALSE, + + /* output phase assignment and assignment of inputs to two-bit decoders */ + "opo", KEY_opo, 1, TRUE, TRUE, + "opoall", KEY_opoall, 1, TRUE, TRUE, + "pair", KEY_pair, 1, TRUE, TRUE, + "pairall", KEY_pairall, 1, TRUE, TRUE, + + /* Ways to check covers */ + "check", KEY_check, 1, TRUE, TRUE, + "stats", KEY_stats, 1, FALSE, FALSE, + "verify", KEY_verify, 2, FALSE, TRUE, + "PLAverify", KEY_PLA_verify, 2, FALSE, TRUE, + + /* hacks */ + "equiv", KEY_equiv, 1, TRUE, TRUE, + "map", KEY_map, 1, FALSE, FALSE, + "mapdc", KEY_mapdc, 1, FALSE, FALSE, + "fsm", KEY_fsm, 1, FALSE, TRUE, + + /* the basic boolean operations on covers */ + "contain", KEY_contain, 1, FALSE, FALSE, + "d1merge", KEY_d1merge, 1, FALSE, FALSE, + "d1merge_in", KEY_d1merge_in, 1, FALSE, FALSE, + "disjoint", KEY_disjoint, 1, TRUE, FALSE, + "dsharp", KEY_dsharp, 2, FALSE, FALSE, + "intersect", KEY_intersect, 2, FALSE, FALSE, + "minterms", KEY_minterms, 1, FALSE, FALSE, + "primes", KEY_primes, 1, FALSE, TRUE, + "separate", KEY_separate, 1, TRUE, TRUE, + "sharp", KEY_sharp, 2, FALSE, FALSE, + "union", KEY_union, 2, FALSE, FALSE, + "xor", KEY_xor, 2, TRUE, TRUE, + + /* debugging only -- call each step of the espresso algorithm */ + "essen", KEY_essen, 1, FALSE, TRUE, + "expand", KEY_expand, 1, TRUE, FALSE, + "gasp", KEY_gasp, 1, TRUE, TRUE, + "irred", KEY_irred, 1, FALSE, TRUE, + "make_sparse", KEY_make_sparse, 1, TRUE, TRUE, + "reduce", KEY_reduce, 1, FALSE, TRUE, + "taut", KEY_taut, 1, FALSE, FALSE, + "super_gasp", KEY_super_gasp, 1, TRUE, TRUE, + "lexsort", KEY_lexsort, 1, FALSE, FALSE, + "test", KEY_test, 1, TRUE, TRUE, + 0, KEY_unknown, 0, FALSE, FALSE /* must be last */ +}; + + +struct { + char *name; + int value; +} debug_table[] = { + "", EXPAND + ESSEN + IRRED + REDUCE + SPARSE + GASP + SHARP + MINCOV, + "compl", COMPL, "essen", ESSEN, + "expand", EXPAND, "expand1", EXPAND1|EXPAND, + "irred", IRRED, "irred1", IRRED1|IRRED, + "reduce", REDUCE, "reduce1", REDUCE1|REDUCE, + "mincov", MINCOV, "mincov1", MINCOV1|MINCOV, + "sparse", SPARSE, "sharp", SHARP, + "taut", TAUT, "gasp", GASP, + "exact", EXACT, + 0, +}; + + +struct { + char *name; + int *variable; + int value; +} esp_opt_table[] = { + "eat", &echo_comments, FALSE, + "eatdots", &echo_unknown_commands, FALSE, + "fast", &single_expand, TRUE, + "kiss", &kiss, TRUE, + "ness", &remove_essential, FALSE, + "nirr", &force_irredundant, FALSE, + "nunwrap", &unwrap_onset, FALSE, + "onset", &recompute_onset, TRUE, + "pos", &pos, TRUE, + "random", &use_random_order, TRUE, + "strong", &use_super_gasp, TRUE, + 0, +}; diff --git a/benchmarks/benchmarks/espresso/map.c b/benchmarks/benchmarks/espresso/map.c new file mode 100644 index 0000000..d0c041d --- /dev/null +++ b/benchmarks/benchmarks/espresso/map.c @@ -0,0 +1,106 @@ +#include "espresso.h" + +static pcube Gcube; +static pset Gminterm; + +pset minterms(T) +pcover T; +{ + int size, var; + register pcube last; + + size = 1; + for(var = 0; var < cube.num_vars; var++) + size *= cube.part_size[var]; + Gminterm = set_new(size); + + foreach_set(T, last, Gcube) + explode(cube.num_vars-1, 0); + + return Gminterm; +} + + +void explode(var, z) +int var, z; +{ + int i, last = cube.last_part[var]; + for(i=cube.first_part[var], z *= cube.part_size[var]; i<=last; i++, z++) + if (is_in_set(Gcube, i)) + if (var == 0) + set_insert(Gminterm, z); + else + explode(var-1, z); +} + + +static int mapindex[16][16] = { + 0, 1, 3, 2, 16, 17, 19, 18, 80, 81, 83, 82, 64, 65, 67, 66, + 4, 5, 7, 6, 20, 21, 23, 22, 84, 85, 87, 86, 68, 69, 71, 70, + 12, 13, 15, 14, 28, 29, 31, 30, 92, 93, 95, 94, 76, 77, 79, 78, + 8, 9, 11, 10, 24, 25, 27, 26, 88, 89, 91, 90, 72, 73, 75, 74, + + 32, 33, 35, 34, 48, 49, 51, 50, 112,113,115,114, 96, 97, 99, 98, + 36, 37, 39, 38, 52, 53, 55, 54, 116,117,119,118, 100,101,103,102, + 44, 45, 47, 46, 60, 61, 63, 62, 124,125,127,126, 108,109,111,110, + 40, 41, 43, 42, 56, 57, 59, 58, 120,121,123,122, 104,105,107,106, + + + 160,161,163,162, 176,177,179,178, 240,241,243,242, 224,225,227,226, + 164,165,167,166, 180,181,183,182, 244,245,247,246, 228,229,231,230, + 172,173,175,174, 188,189,191,190, 252,253,255,254, 236,237,239,238, + 168,169,171,170, 184,185,187,186, 248,249,251,250, 232,233,235,234, + + 128,129,131,130, 144,145,147,146, 208,209,211,210, 192,193,195,194, + 132,133,135,134, 148,149,151,150, 212,213,215,214, 196,197,199,198, + 140,141,143,142, 156,157,159,158, 220,221,223,222, 204,205,207,206, + 136,137,139,138, 152,153,155,154, 216,217,219,218, 200,201,203,202 +}; + +#define POWER2(n) (1 << n) +void map(T) +pcover T; +{ + int j, k, l, other_input_offset, output_offset, outnum, ind; + int largest_input_ind, numout; + char c; + pset m; + bool some_output; + + m = minterms(T); + largest_input_ind = POWER2(cube.num_binary_vars); + numout = cube.part_size[cube.num_vars-1]; + + for(outnum = 0; outnum < numout; outnum++) { + output_offset = outnum * largest_input_ind; + printf("\n\nOutput space # %d\n", outnum); + for(l = 0; l <= MAX(cube.num_binary_vars - 8, 0); l++) { + other_input_offset = l * 256; + for(k = 0; k < 16; k++) { + some_output = FALSE; + for(j = 0; j < 16; j++) { + ind = mapindex[k][j] + other_input_offset; + if (ind < largest_input_ind) { + c = is_in_set(m, ind+output_offset) ? '1' : '.'; + putchar(c); + some_output = TRUE; + } + if ((j+1)%4 == 0) + putchar(' '); + if ((j+1)%8 == 0) + printf(" "); + } + if (some_output) + putchar('\n'); + if ((k+1)%4 == 0) { + if (k != 15 && mapindex[k+1][0] >= largest_input_ind) + break; + putchar('\n'); + } + if ((k+1)%8 == 0) + putchar('\n'); + } + } + } + set_free(m); +} diff --git a/benchmarks/benchmarks/espresso/matrix.c b/benchmarks/benchmarks/espresso/matrix.c new file mode 100644 index 0000000..b012a3e --- /dev/null +++ b/benchmarks/benchmarks/espresso/matrix.c @@ -0,0 +1,566 @@ +#include "espresso.h" +#include "port.h" +#include "sparse_int.h" + +/* + * free-lists are only used if 'FAST_AND_LOOSE' is set; this is because + * we lose the debugging capability of libmm_t which trashes objects when + * they are free'd. However, FAST_AND_LOOSE is much faster if matrices + * are created and freed frequently. + */ + +#ifdef FAST_AND_LOOSE +sm_element *sm_element_freelist; +sm_row *sm_row_freelist; +sm_col *sm_col_freelist; +#endif + + +sm_matrix * +sm_alloc() +{ + register sm_matrix *A; + + A = ALLOC(sm_matrix, 1); + A->rows = NIL(sm_row *); + A->cols = NIL(sm_col *); + A->nrows = A->ncols = 0; + A->rows_size = A->cols_size = 0; + A->first_row = A->last_row = NIL(sm_row); + A->first_col = A->last_col = NIL(sm_col); + A->user_word = NIL(char); /* for our user ... */ + return A; +} + + +sm_matrix * +sm_alloc_size(row, col) +int row, col; +{ + register sm_matrix *A; + + A = sm_alloc(); + sm_resize(A, row, col); + return A; +} + + +void +sm_free(A) +sm_matrix *A; +{ +#ifdef FAST_AND_LOOSE + register sm_row *prow; + + if (A->first_row != 0) { + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + /* add the elements to the free list of elements */ + prow->last_col->next_col = sm_element_freelist; + sm_element_freelist = prow->first_col; + } + + /* Add the linked list of rows to the row-free-list */ + A->last_row->next_row = sm_row_freelist; + sm_row_freelist = A->first_row; + + /* Add the linked list of cols to the col-free-list */ + A->last_col->next_col = sm_col_freelist; + sm_col_freelist = A->first_col; + } +#else + register sm_row *prow, *pnext_row; + register sm_col *pcol, *pnext_col; + + for(prow = A->first_row; prow != 0; prow = pnext_row) { + pnext_row = prow->next_row; + sm_row_free(prow); + } + for(pcol = A->first_col; pcol != 0; pcol = pnext_col) { + pnext_col = pcol->next_col; + pcol->first_row = pcol->last_row = NIL(sm_element); + sm_col_free(pcol); + } +#endif + + /* Free the arrays to map row/col numbers into pointers */ + FREE(A->rows); + FREE(A->cols); + FREE(A); +} + + +sm_matrix * +sm_dup(A) +sm_matrix *A; +{ + register sm_row *prow; + register sm_element *p; + register sm_matrix *B; + + B = sm_alloc(); + if (A->last_row != 0) { + sm_resize(B, A->last_row->row_num, A->last_col->col_num); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_insert(B, p->row_num, p->col_num); + } + } + } + return B; +} + + +void +sm_resize(A, row, col) +register sm_matrix *A; +int row, col; +{ + register int i, new_size; + + if (row >= A->rows_size) { + new_size = MAX(A->rows_size*2, row+1); + A->rows = REALLOC(sm_row *, A->rows, new_size); + for(i = A->rows_size; i < new_size; i++) { + A->rows[i] = NIL(sm_row); + } + A->rows_size = new_size; + } + + if (col >= A->cols_size) { + new_size = MAX(A->cols_size*2, col+1); + A->cols = REALLOC(sm_col *, A->cols, new_size); + for(i = A->cols_size; i < new_size; i++) { + A->cols[i] = NIL(sm_col); + } + A->cols_size = new_size; + } +} + + +/* + * insert -- insert a value into the matrix + */ +sm_element * +sm_insert(A, row, col) +register sm_matrix *A; +register int row, col; +{ + register sm_row *prow; + register sm_col *pcol; + register sm_element *element; + sm_element *save_element; + + if (row >= A->rows_size || col >= A->cols_size) { + sm_resize(A, row, col); + } + + prow = A->rows[row]; + if (prow == NIL(sm_row)) { + prow = A->rows[row] = sm_row_alloc(); + prow->row_num = row; + sorted_insert(sm_row, A->first_row, A->last_row, A->nrows, + next_row, prev_row, row_num, row, prow); + } + + pcol = A->cols[col]; + if (pcol == NIL(sm_col)) { + pcol = A->cols[col] = sm_col_alloc(); + pcol->col_num = col; + sorted_insert(sm_col, A->first_col, A->last_col, A->ncols, + next_col, prev_col, col_num, col, pcol); + } + + /* get a new item, save its address */ + sm_element_alloc(element); + save_element = element; + + /* insert it into the row list */ + sorted_insert(sm_element, prow->first_col, prow->last_col, + prow->length, next_col, prev_col, col_num, col, element); + + /* if it was used, also insert it into the column list */ + if (element == save_element) { + sorted_insert(sm_element, pcol->first_row, pcol->last_row, + pcol->length, next_row, prev_row, row_num, row, element); + } else { + /* otherwise, it was already in matrix -- free element we allocated */ + sm_element_free(save_element); + } + return element; +} + + +sm_element * +sm_find(A, rownum, colnum) +sm_matrix *A; +int rownum, colnum; +{ + sm_row *prow; + sm_col *pcol; + + prow = sm_get_row(A, rownum); + if (prow == NIL(sm_row)) { + return NIL(sm_element); + } else { + pcol = sm_get_col(A, colnum); + if (pcol == NIL(sm_col)) { + return NIL(sm_element); + } + if (prow->length < pcol->length) { + return sm_row_find(prow, colnum); + } else { + return sm_col_find(pcol, rownum); + } + } +} + + +void +sm_remove(A, rownum, colnum) +sm_matrix *A; +int rownum, colnum; +{ + sm_remove_element(A, sm_find(A, rownum, colnum)); +} + + + +void +sm_remove_element(A, p) +register sm_matrix *A; +register sm_element *p; +{ + register sm_row *prow; + register sm_col *pcol; + + if (p == 0) return; + + /* Unlink the element from its row */ + prow = sm_get_row(A, p->row_num); + dll_unlink(p, prow->first_col, prow->last_col, + next_col, prev_col, prow->length); + + /* if no more elements in the row, discard the row header */ + if (prow->first_col == NIL(sm_element)) { + sm_delrow(A, p->row_num); + } + + /* Unlink the element from its column */ + pcol = sm_get_col(A, p->col_num); + dll_unlink(p, pcol->first_row, pcol->last_row, + next_row, prev_row, pcol->length); + + /* if no more elements in the column, discard the column header */ + if (pcol->first_row == NIL(sm_element)) { + sm_delcol(A, p->col_num); + } + + sm_element_free(p); +} + +void +sm_delrow(A, i) +sm_matrix *A; +int i; +{ + register sm_element *p, *pnext; + sm_col *pcol; + sm_row *prow; + + prow = sm_get_row(A, i); + if (prow != NIL(sm_row)) { + /* walk across the row */ + for(p = prow->first_col; p != 0; p = pnext) { + pnext = p->next_col; + + /* unlink the item from the column (and delete it) */ + pcol = sm_get_col(A, p->col_num); + sm_col_remove_element(pcol, p); + + /* discard the column if it is now empty */ + if (pcol->first_row == NIL(sm_element)) { + sm_delcol(A, pcol->col_num); + } + } + + /* discard the row -- we already threw away the elements */ + A->rows[i] = NIL(sm_row); + dll_unlink(prow, A->first_row, A->last_row, + next_row, prev_row, A->nrows); + prow->first_col = prow->last_col = NIL(sm_element); + sm_row_free(prow); + } +} + +void +sm_delcol(A, i) +sm_matrix *A; +int i; +{ + register sm_element *p, *pnext; + sm_row *prow; + sm_col *pcol; + + pcol = sm_get_col(A, i); + if (pcol != NIL(sm_col)) { + /* walk down the column */ + for(p = pcol->first_row; p != 0; p = pnext) { + pnext = p->next_row; + + /* unlink the element from the row (and delete it) */ + prow = sm_get_row(A, p->row_num); + sm_row_remove_element(prow, p); + + /* discard the row if it is now empty */ + if (prow->first_col == NIL(sm_element)) { + sm_delrow(A, prow->row_num); + } + } + + /* discard the column -- we already threw away the elements */ + A->cols[i] = NIL(sm_col); + dll_unlink(pcol, A->first_col, A->last_col, + next_col, prev_col, A->ncols); + pcol->first_row = pcol->last_row = NIL(sm_element); + sm_col_free(pcol); + } +} + +void +sm_copy_row(dest, dest_row, prow) +register sm_matrix *dest; +int dest_row; +sm_row *prow; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_insert(dest, dest_row, p->col_num); + } +} + + +void +sm_copy_col(dest, dest_col, pcol) +register sm_matrix *dest; +int dest_col; +sm_col *pcol; +{ + register sm_element *p; + + for(p = pcol->first_row; p != 0; p = p->next_row) { + (void) sm_insert(dest, dest_col, p->row_num); + } +} + + +sm_row * +sm_longest_row(A) +sm_matrix *A; +{ + register sm_row *large_row, *prow; + register int max_length; + + max_length = 0; + large_row = NIL(sm_row); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + if (prow->length > max_length) { + max_length = prow->length; + large_row = prow; + } + } + return large_row; +} + + +sm_col * +sm_longest_col(A) +sm_matrix *A; +{ + register sm_col *large_col, *pcol; + register int max_length; + + max_length = 0; + large_col = NIL(sm_col); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + if (pcol->length > max_length) { + max_length = pcol->length; + large_col = pcol; + } + } + return large_col; +} + +int +sm_num_elements(A) +sm_matrix *A; +{ + register sm_row *prow; + register int num; + + num = 0; + sm_foreach_row(A, prow) { + num += prow->length; + } + return num; +} + +int +sm_read(fp, A) +FILE *fp; +sm_matrix **A; +{ + int i, j, err; + + *A = sm_alloc(); + while (! feof(fp)) { + err = fscanf(fp, "%d %d", &i, &j); + if (err == EOF) { + return 1; + } else if (err != 2) { + return 0; + } + (void) sm_insert(*A, i, j); + } + return 1; +} + + +int +sm_read_compressed(fp, A) +FILE *fp; +sm_matrix **A; +{ + int i, j, k, nrows, ncols; + unsigned long x; + + *A = sm_alloc(); + if (fscanf(fp, "%d %d", &nrows, &ncols) != 2) { + return 0; + } + sm_resize(*A, nrows, ncols); + + for(i = 0; i < nrows; i++) { + if (fscanf(fp, "%lx", &x) != 1) { + return 0; + } + for(j = 0; j < ncols; j += 32) { + if (fscanf(fp, "%lx", &x) != 1) { + return 0; + } + for(k = j; x != 0; x >>= 1, k++) { + if (x & 1) { + (void) sm_insert(*A, i, k); + } + } + } + } + return 1; +} + + +void +sm_write(fp, A) +FILE *fp; +sm_matrix *A; +{ + register sm_row *prow; + register sm_element *p; + + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) fprintf(fp, "%d %d\n", p->row_num, p->col_num); + } + } +} + +void +sm_print(fp, A) +FILE *fp; +sm_matrix *A; +{ + register sm_row *prow; + register sm_col *pcol; + int c; + + if (A->last_col->col_num >= 100) { + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "%d", (pcol->col_num / 100)%10); + } + putc('\n', fp); + } + + if (A->last_col->col_num >= 10) { + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "%d", (pcol->col_num / 10)%10); + } + putc('\n', fp); + } + + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "%d", pcol->col_num % 10); + } + putc('\n', fp); + + (void) fprintf(fp, " "); + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + (void) fprintf(fp, "-"); + } + putc('\n', fp); + + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + (void) fprintf(fp, "%3d:", prow->row_num); + + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + c = sm_row_find(prow, pcol->col_num) ? '1' : '.'; + putc(c, fp); + } + putc('\n', fp); + } +} + + +void +sm_dump(A, s, max) +sm_matrix *A; +char *s; +int max; +{ + FILE *fp = stdout; + + (void) fprintf(fp, "%s %d rows by %d cols\n", s, A->nrows, A->ncols); + if (A->nrows < max) { + sm_print(fp, A); + } +} + +void +sm_cleanup() +{ +#ifdef FAST_AND_LOOSE + register sm_element *p, *pnext; + register sm_row *prow, *pnextrow; + register sm_col *pcol, *pnextcol; + + for(p = sm_element_freelist; p != 0; p = pnext) { + pnext = p->next_col; + FREE(p); + } + sm_element_freelist = 0; + + for(prow = sm_row_freelist; prow != 0; prow = pnextrow) { + pnextrow = prow->next_row; + FREE(prow); + } + sm_row_freelist = 0; + + for(pcol = sm_col_freelist; pcol != 0; pcol = pnextcol) { + pnextcol = pcol->next_col; + FREE(pcol); + } + sm_col_freelist = 0; +#endif +} diff --git a/benchmarks/benchmarks/espresso/mincov.c b/benchmarks/benchmarks/espresso/mincov.c new file mode 100644 index 0000000..e940e5d --- /dev/null +++ b/benchmarks/benchmarks/espresso/mincov.c @@ -0,0 +1,370 @@ +#include "espresso.h" +#include "mincov_int.h" + +/* + * mincov.c + */ + +#define USE_GIMPEL +#define USE_INDEP_SET + +static int select_column(); +static void select_essential(); +static int verify_cover(); + +#define fail(why) {\ + (void) fprintf(stderr, "Fatal error: file %s, line %d\n%s\n",\ + __FILE__, __LINE__, why);\ + (void) fflush(stdout);\ + abort();\ +} + +sm_row * +sm_minimum_cover(A, weight, heuristic, debug_level) +sm_matrix *A; +int *weight; +int heuristic; /* set to 1 for a heuristic covering */ +int debug_level; /* how deep in the recursion to provide info */ +{ + stats_t stats; + solution_t *best, *select; + sm_row *prow, *sol; + sm_col *pcol; + sm_matrix *dup_A; + int nelem, bound; + double sparsity; + + /* Avoid sillyness */ + if (A->nrows <= 0) { + return sm_row_alloc(); /* easy to cover */ + } + + /* Initialize debugging structure */ + stats.start_time = util_cpu_time(); + stats.debug = debug_level > 0; + stats.max_print_depth = debug_level; + stats.max_depth = -1; + stats.nodes = 0; + stats.component = stats.comp_count = 0; + stats.gimpel = stats.gimpel_count = 0; + stats.no_branching = heuristic != 0; + stats.lower_bound = -1; + + /* Check the matrix sparsity */ + nelem = 0; + sm_foreach_row(A, prow) { + nelem += prow->length; + } + sparsity = (double) nelem / (double) (A->nrows * A->ncols); + + /* Determine an upper bound on the solution */ + bound = 1; + sm_foreach_col(A, pcol) { + bound += WEIGHT(weight, pcol->col_num); + } + + /* Perform the covering */ + select = solution_alloc(); + dup_A = sm_dup(A); + best = sm_mincov(dup_A, select, weight, 0, bound, 0, &stats); + sm_free(dup_A); + solution_free(select); + + if (stats.debug) { + if (stats.no_branching) { + (void) printf("**** heuristic covering ...\n"); + (void) printf("lower bound = %d\n", stats.lower_bound); + } + (void) printf("matrix = %d by %d with %d elements (%4.3f%%)\n", + A->nrows, A->ncols, nelem, sparsity * 100.0); + (void) printf("cover size = %d elements\n", best->row->length); + (void) printf("cover cost = %d\n", best->cost); + (void) printf("time = %s\n", + util_print_time(util_cpu_time() - stats.start_time)); + (void) printf("components = %d\n", stats.comp_count); + (void) printf("gimpel = %d\n", stats.gimpel_count); + (void) printf("nodes = %d\n", stats.nodes); + (void) printf("max_depth = %d\n", stats.max_depth); + } + + sol = sm_row_dup(best->row); + if (! verify_cover(A, sol)) { + fail("mincov: internal error -- cover verification failed\n"); + } + solution_free(best); + return sol; +} + +/* + * Find the best cover for 'A' (given that 'select' already selected); + * + * - abort search if a solution cannot be found which beats 'bound' + * + * - if any solution meets 'lower_bound', then it is the optimum solution + * and can be returned without further work. + */ + +solution_t * +sm_mincov(A, select, weight, lb, bound, depth, stats) +sm_matrix *A; +solution_t *select; +int *weight; +int lb; +int bound; +int depth; +stats_t *stats; +{ + sm_matrix *A1, *A2, *L, *R; + sm_element *p; + solution_t *select1, *select2, *best, *best1, *best2, *indep; + int pick, lb_new, debug; + + /* Start out with some debugging information */ + stats->nodes++; + if (depth > stats->max_depth) stats->max_depth = depth; + debug = stats->debug && (depth <= stats->max_print_depth); + + /* Apply row dominance, column dominance, and select essentials */ + select_essential(A, select, weight, bound); + if (select->cost >= bound) { + return NIL(solution_t); + } + + /* See if gimpel's reduction technique applies ... */ +#ifdef USE_GIMPEL + if ( weight == NIL(int)) { /* hack until we fix it */ + if (gimpel_reduce(A, select, weight, lb, bound, depth, stats, &best)) { + return best; + } + } +#endif + +#ifdef USE_INDEP_SET + /* Determine bound from here to final solution using independent-set */ + indep = sm_maximal_independent_set(A, weight); + + /* make sure the lower bound is monotonically increasing */ + lb_new = MAX(select->cost + indep->cost, lb); + pick = select_column(A, weight, indep); + solution_free(indep); +#else + lb_new = select->cost + (A->nrows > 0); + pick = select_column(A, weight, NIL(solution_t)); +#endif + + if (depth == 0) { + stats->lower_bound = lb_new + stats->gimpel; + } + + if (debug) { + (void) printf("ABSMIN[%2d]%s", depth, stats->component ? "*" : " "); + (void) printf(" %3dx%3d sel=%3d bnd=%3d lb=%3d %12s ", + A->nrows, A->ncols, select->cost + stats->gimpel, + bound + stats->gimpel, lb_new + stats->gimpel, + util_print_time(util_cpu_time()-stats->start_time)); + } + + /* Check for bounding based on no better solution possible */ + if (lb_new >= bound) { + if (debug) (void) printf("bounded\n"); + best = NIL(solution_t); + + + /* Check for new best solution */ + } else if (A->nrows == 0) { + best = solution_dup(select); + if (debug) (void) printf("BEST\n"); + if (stats->debug && stats->component == 0) { + (void) printf("new 'best' solution %d at level %d (time is %s)\n", + best->cost + stats->gimpel, depth, + util_print_time(util_cpu_time() - stats->start_time)); + } + + + /* Check for a partition of the problem */ + } else if (sm_block_partition(A, &L, &R)) { + /* Make L the smaller problem */ + if (L->ncols > R->ncols) { + A1 = L; + L = R; + R = A1; + } + if (debug) (void) printf("comp %d %d\n", L->nrows, R->nrows); + stats->comp_count++; + + /* Solve problem for L */ + select1 = solution_alloc(); + stats->component++; + best1 = sm_mincov(L, select1, weight, 0, + bound-select->cost, depth+1, stats); + stats->component--; + solution_free(select1); + sm_free(L); + + /* Add best solution to the selected set */ + if (best1 == NIL(solution_t)) { + best = NIL(solution_t); + } else { + for(p = best1->row->first_col; p != 0; p = p->next_col) { + solution_add(select, weight, p->col_num); + } + solution_free(best1); + + /* recur for the remaining block */ + best = sm_mincov(R, select, weight, lb_new, bound, depth+1, stats); + } + sm_free(R); + + /* We've tried as hard as possible, but now we must split and recur */ + } else { + if (debug) (void) printf("pick=%d\n", pick); + + /* Assume we choose this column to be in the covering set */ + A1 = sm_dup(A); + select1 = solution_dup(select); + solution_accept(select1, A1, weight, pick); + best1 = sm_mincov(A1, select1, weight, lb_new, bound, depth+1, stats); + solution_free(select1); + sm_free(A1); + + /* Update the upper bound if we found a better solution */ + if (best1 != NIL(solution_t) && bound > best1->cost) { + bound = best1->cost; + } + + /* See if this is a heuristic covering (no branching) */ + if (stats->no_branching) { + return best1; + } + + /* Check for reaching lower bound -- if so, don't actually branch */ + if (best1 != NIL(solution_t) && best1->cost == lb_new) { + return best1; + } + + /* Now assume we cannot have that column */ + A2 = sm_dup(A); + select2 = solution_dup(select); + solution_reject(select2, A2, weight, pick); + best2 = sm_mincov(A2, select2, weight, lb_new, bound, depth+1, stats); + solution_free(select2); + sm_free(A2); + + best = solution_choose_best(best1, best2); + } + + return best; +} + +static int +select_column(A, weight, indep) +sm_matrix *A; +int *weight; +solution_t *indep; +{ + register sm_col *pcol; + register sm_row *prow, *indep_cols; + register sm_element *p, *p1; + double w, best; + int best_col; + + indep_cols = sm_row_alloc(); + if (indep != NIL(solution_t)) { + /* Find which columns are in the independent sets */ + for(p = indep->row->first_col; p != 0; p = p->next_col) { + prow = sm_get_row(A, p->col_num); + for(p1 = prow->first_col; p1 != 0; p1 = p1->next_col) { + (void) sm_row_insert(indep_cols, p1->col_num); + } + } + } else { + /* select out of all columns */ + sm_foreach_col(A, pcol) { + (void) sm_row_insert(indep_cols, pcol->col_num); + } + } + + /* Find the best column */ + best_col = -1; + best = -1; + + /* Consider only columns which are in some independent row */ + sm_foreach_row_element(indep_cols, p1) { + pcol = sm_get_col(A, p1->col_num); + + /* Compute the total 'value' of all things covered by the column */ + w = 0.0; + for(p = pcol->first_row; p != 0; p = p->next_row) { + prow = sm_get_row(A, p->row_num); + w += 1.0 / ((double) prow->length - 1.0); + } + + /* divide this by the relative cost of choosing this column */ + w = w / (double) WEIGHT(weight, pcol->col_num); + + /* maximize this ratio */ + if (w > best) { + best_col = pcol->col_num; + best = w; + } + } + + sm_row_free(indep_cols); + return best_col; +} + +static void +select_essential(A, select, weight, bound) +sm_matrix *A; +solution_t *select; +int *weight; +int bound; /* must beat this solution */ +{ + register sm_element *p; + register sm_row *prow, *essen; + int delcols, delrows, essen_count; + + do { + /* Check for dominated columns */ + delcols = sm_col_dominance(A, weight); + + /* Find the rows with only 1 element (the essentials) */ + essen = sm_row_alloc(); + sm_foreach_row(A, prow) { + if (prow->length == 1) { + (void) sm_row_insert(essen, prow->first_col->col_num); + } + } + + /* Select all of the elements */ + sm_foreach_row_element(essen, p) { + solution_accept(select, A, weight, p->col_num); + /* Make sure solution still looks good */ + if (select->cost >= bound) { + sm_row_free(essen); + return; + } + } + essen_count = essen->length; + sm_row_free(essen); + + /* Check for dominated rows */ + delrows = sm_row_dominance(A); + + } while (delcols > 0 || delrows > 0 || essen_count > 0); +} + +static int +verify_cover(A, cover) +sm_matrix *A; +sm_row *cover; +{ + sm_row *prow; + + sm_foreach_row(A, prow) { + if (! sm_row_intersects(prow, cover)) { + return 0; + } + } + return 1; +} diff --git a/benchmarks/benchmarks/espresso/mincov.h b/benchmarks/benchmarks/espresso/mincov.h new file mode 100644 index 0000000..f6a0425 --- /dev/null +++ b/benchmarks/benchmarks/espresso/mincov.h @@ -0,0 +1,2 @@ +/* exported */ +extern sm_row *sm_minimum_cover(); diff --git a/benchmarks/benchmarks/espresso/mincov_int.h b/benchmarks/benchmarks/espresso/mincov_int.h new file mode 100644 index 0000000..a9f932e --- /dev/null +++ b/benchmarks/benchmarks/espresso/mincov_int.h @@ -0,0 +1,44 @@ +#include "port.h" +#include "utility.h" +#include "sparse.h" +#include "mincov.h" + + +typedef struct stats_struct stats_t; +struct stats_struct { + int debug; /* 1 if debugging is enabled */ + int max_print_depth; /* dump stats for levels up to this level */ + int max_depth; /* deepest the recursion has gone */ + int nodes; /* total nodes visited */ + int component; /* currently solving a component */ + int comp_count; /* number of components detected */ + int gimpel_count; /* number of times Gimpel reduction applied */ + int gimpel; /* currently inside Gimpel reduction */ + long start_time; /* cpu time when the covering started */ + int no_branching; + int lower_bound; +}; + + + +typedef struct solution_struct solution_t; +struct solution_struct { + sm_row *row; + int cost; +}; + + +extern solution_t *solution_alloc(); +extern void solution_free(); +extern solution_t *solution_dup(); +extern void solution_accept(); +extern void solution_reject(); +extern void solution_add(); +extern solution_t *solution_choose_best(); + +extern solution_t *sm_maximal_independent_set(); +extern solution_t *sm_mincov(); +extern int gimpel_reduce(); + + +#define WEIGHT(weight, col) (weight == NIL(int) ? 1 : weight[col]) diff --git a/benchmarks/benchmarks/espresso/opo.c b/benchmarks/benchmarks/espresso/opo.c new file mode 100644 index 0000000..1951cb9 --- /dev/null +++ b/benchmarks/benchmarks/espresso/opo.c @@ -0,0 +1,615 @@ +#include "espresso.h" + +/* + * Phase assignment technique (T. Sasao): + * + * 1. create a function with 2*m outputs which implements the + * original function and its complement for each output + * + * 2. minimize this function + * + * 3. choose the minimum number of prime implicants from the + * result of step 2 which are needed to realize either a function + * or its complement for each output + * + * Step 3 is performed in a rather crude way -- by simply multiplying + * out a large expression of the form: + * + * I = (ab + cdef)(acd + bgh) ... + * + * which is a product of m expressions where each expression has two + * product terms -- one representing which primes are needed for the + * function, and one representing which primes are needed for the + * complement. The largest product term resulting shows which primes + * to keep to implement one function or the other for each output. + * For problems with many outputs, this may grind to a + * halt. + * + * Untried: form complement of I and use unate_complement ... + * + * I have unsuccessfully tried several modifications to the basic + * algorithm. The first is quite simple: use Sasao's technique, but + * only commit to a single output at a time (rather than all + * outputs). The goal would be that the later minimizations can "take + * into account" the partial assignment at each step. This is + * expensive (m+1 minimizations rather than 2), and the results are + * discouraging. + * + * The second modification is rather complicated. The result from the + * minimization in step 2 is guaranteed to be minimal. Hence, for + * each output, the set of primes with a 1 in that output are both + * necessary and sufficient to implement the function. Espresso + * achieves the minimality using the routine MAKE_SPARSE. The + * modification is to prevent MAKE_SPARSE from running. Hence, there + * are potentially many subsets of the set of primes with a 1 in a + * column which can be used to implement that output. We use + * IRREDUNDANT to enumerate all possible subsets and then proceed as + * before. + */ + +static int opo_no_make_sparse; +static int opo_repeated; +static int opo_exact; +static void minimize(); + +void phase_assignment(PLA, opo_strategy) +pPLA PLA; +int opo_strategy; +{ + opo_no_make_sparse = opo_strategy % 2; + skip_make_sparse = opo_no_make_sparse; + opo_repeated = (opo_strategy / 2) % 2; + opo_exact = (opo_strategy / 4) % 2; + + /* Determine a phase assignment */ + if (PLA->phase != NULL) { + FREE(PLA->phase); + } + + if (opo_repeated) { + PLA->phase = set_save(cube.fullset); + repeated_phase_assignment(PLA); + } else { + PLA->phase = find_phase(PLA, 0, (pcube) NULL); + } + + /* Now minimize with this assignment */ + skip_make_sparse = FALSE; + (void) set_phase(PLA); + minimize(PLA); +} + +/* + * repeated_phase_assignment -- an alternate strategy which commits + * to a single phase assignment a step at a time. Performs m + 1 + * minimizations ! + */ +void repeated_phase_assignment(PLA) +pPLA PLA; +{ + int i; + pcube phase; + + for(i = 0; i < cube.part_size[cube.output]; i++) { + + /* Find best assignment for all undecided outputs */ + phase = find_phase(PLA, i, PLA->phase); + + /* Commit for only a single output ... */ + if (! is_in_set(phase, cube.first_part[cube.output] + i)) { + set_remove(PLA->phase, cube.first_part[cube.output] + i); + } + + if (trace || summary) { + printf("\nOPO loop for output #%d\n", i); + printf("PLA->phase is %s\n", pc1(PLA->phase)); + printf("phase is %s\n", pc1(phase)); + } + set_free(phase); + } +} + + +/* + * find_phase -- find a phase assignment for the PLA for all outputs starting + * with output number first_output. + */ +pcube find_phase(PLA, first_output, phase1) +pPLA PLA; +int first_output; +pcube phase1; +{ + pcube phase; + pPLA PLA1; + + phase = set_save(cube.fullset); + + /* setup the double-phase characteristic function, resize the cube */ + PLA1 = new_PLA(); + PLA1->F = sf_save(PLA->F); + PLA1->R = sf_save(PLA->R); + PLA1->D = sf_save(PLA->D); + if (phase1 != NULL) { + PLA1->phase = set_save(phase1); + (void) set_phase(PLA1); + } + EXEC_S(output_phase_setup(PLA1, first_output), "OPO-SETUP ", PLA1->F); + + /* minimize the double-phase function */ + minimize(PLA1); + + /* set the proper phases according to what gives a minimum solution */ + EXEC_S(PLA1->F = opo(phase, PLA1->F, PLA1->D, PLA1->R, first_output), + "OPO ", PLA1->F); + free_PLA(PLA1); + + /* set the cube structure to reflect the old size */ + setdown_cube(); + cube.part_size[cube.output] -= + (cube.part_size[cube.output] - first_output) / 2; + cube_setup(); + + return phase; +} + +/* + * opo -- multiply the expression out to determine a minimum subset of + * primes. + */ + +/*ARGSUSED*/ +pcover opo(phase, T, D, R, first_output) +pcube phase; +pcover T, D, R; +int first_output; +{ + int offset, output, i, last_output, ind; + pset pdest, select, p, p1, last, last1, not_covered, tmp; + pset_family temp, T1, T2; + + /* must select all primes for outputs [0 .. first_output-1] */ + select = set_full(T->count); + for(output = 0; output < first_output; output++) { + ind = cube.first_part[cube.output] + output; + foreachi_set(T, i, p) { + if (is_in_set(p, ind)) { + set_remove(select, i); + } + } + } + + /* Recursively perform the intersections */ + offset = (cube.part_size[cube.output] - first_output) / 2; + last_output = first_output + offset - 1; + temp = opo_recur(T, D, select, offset, first_output, last_output); + + /* largest set is on top -- select primes which are inferred from it */ + pdest = temp->data; + T1 = new_cover(T->count); + foreachi_set(T, i, p) { + if (! is_in_set(pdest, i)) { + T1 = sf_addset(T1, p); + } + } + + set_free(select); + sf_free(temp); + + /* finding phases is difficult -- see which functions are not covered */ + T2 = complement(cube1list(T1)); + not_covered = new_cube(); + tmp = new_cube(); + foreach_set(T, last, p) { + foreach_set(T2, last1, p1) { + if (cdist0(p, p1)) { + (void) set_or(not_covered, not_covered, set_and(tmp, p, p1)); + } + } + } + free_cover(T); + free_cover(T2); + set_free(tmp); + + /* Now reflect the phase choice in a single cube */ + for(output = first_output; output <= last_output; output++) { + ind = cube.first_part[cube.output] + output; + if (is_in_set(not_covered, ind)) { + if (is_in_set(not_covered, ind + offset)) { + fatal("error in output phase assignment"); + } else { + set_remove(phase, ind); + } + } + } + set_free(not_covered); + return T1; +} + +pset_family opo_recur(T, D, select, offset, first, last) +pcover T, D; +pcube select; +int offset, first, last; +{ + static int level = 0; + int middle; + pset_family sl, sr, temp; + + level++; + if (first == last) { +#if 0 + if (opo_no_make_sparse) { + temp = form_cover_table(T, D, select, first, first + offset); + } else { + temp = opo_leaf(T, select, first, first + offset); + } +#else + temp = opo_leaf(T, select, first, first + offset); +#endif + } else { + middle = (first + last) / 2; + sl = opo_recur(T, D, select, offset, first, middle); + sr = opo_recur(T, D, select, offset, middle+1, last); + temp = unate_intersect(sl, sr, level == 1); + if (trace) { + printf("# OPO[%d]: %4d = %4d x %4d, time = %s\n", level - 1, + temp->count, sl->count, sr->count, print_time(ptime())); + (void) fflush(stdout); + } + free_cover(sl); + free_cover(sr); + } + level--; + return temp; +} + + +pset_family opo_leaf(T, select, out1, out2) +register pcover T; +pset select; +int out1, out2; +{ + register pset_family temp; + register pset p, pdest; + register int i; + + out1 += cube.first_part[cube.output]; + out2 += cube.first_part[cube.output]; + + /* Allocate space for the result */ + temp = sf_new(2, T->count); + + /* Find which primes are needed for the ON-set of this fct */ + pdest = GETSET(temp, temp->count++); + (void) set_copy(pdest, select); + foreachi_set(T, i, p) { + if (is_in_set(p, out1)) { + set_remove(pdest, i); + } + } + + /* Find which primes are needed for the OFF-set of this fct */ + pdest = GETSET(temp, temp->count++); + (void) set_copy(pdest, select); + foreachi_set(T, i, p) { + if (is_in_set(p, out2)) { + set_remove(pdest, i); + } + } + + return temp; +} + +#if 0 +pset_family form_cover_table(F, D, select, f, fbar) +pcover F, D; +pset select; +int f, fbar; /* indices of f and fbar in the output part */ +{ + register int i; + register pcube p; + pset_family f_table, fbar_table; + + /* setup required for fcube_is_covered */ + Rp_size = F->count; + Rp_start = set_new(Rp_size); + foreachi_set(F, i, p) { + PUTSIZE(p, i); + } + foreachi_set(D, i, p) { + RESET(p, REDUND); + } + + f_table = find_covers(F, D, select, f); + fbar_table = find_covers(F, D, select, fbar); + f_table = sf_append(f_table, fbar_table); + + set_free(Rp_start); + return f_table; +} + + +pset_family find_covers(F, D, select, n) +pcover F, D; +register pset select; +int n; +{ + register pset p, last, new; + pcover F1; + pcube *Flist; + pset_family f_table, table; + int i; + + n += cube.first_part[cube.output]; + + /* save cubes in this output, and remove the output variable */ + F1 = new_cover(F->count); + foreach_set(F, last, p) + if (is_in_set(p, n)) { + new = GETSET(F1, F1->count++); + set_or(new, p, cube.var_mask[cube.output]); + PUTSIZE(new, SIZE(p)); + SET(new, REDUND); + } + + /* Find ways (sop form) to fail to cover output indexed by n */ + Flist = cube2list(F1, D); + table = sf_new(10, Rp_size); + foreach_set(F1, last, p) { + set_fill(Rp_start, Rp_size); + set_remove(Rp_start, SIZE(p)); + table = sf_append(table, fcube_is_covered(Flist, p)); + RESET(p, REDUND); + } + set_fill(Rp_start, Rp_size); + foreach_set(table, last, p) { + set_diff(p, Rp_start, p); + } + + /* complement this to get possible ways to cover the function */ + for(i = 0; i < Rp_size; i++) { + if (! is_in_set(select, i)) { + p = set_new(Rp_size); + set_insert(p, i); + table = sf_addset(table, p); + set_free(p); + } + } + f_table = unate_compl(table); + + /* what a pain, but we need bitwise complement of this */ + set_fill(Rp_start, Rp_size); + foreach_set(f_table, last, p) { + set_diff(p, Rp_start, p); + } + + free_cubelist(Flist); + sf_free(F1); + return f_table; +} +#endif + +/* + * Take a PLA (ON-set, OFF-set and DC-set) and create the + * "double-phase characteristic function" which is merely a new + * function which has twice as many outputs and realizes both the + * function and the complement. + * + * The cube structure is assumed to represent the PLA upon entering. + * It will be modified to represent the double-phase function upon + * exit. + * + * Only the outputs numbered starting with "first_output" are + * duplicated in the output part + */ + +output_phase_setup(PLA, first_output) +INOUT pPLA PLA; +int first_output; +{ + pcover F, R, D; + pcube mask, mask1, last; + int first_part, offset; + bool save; + register pcube p, pr, pf; + register int i, last_part; + + if (cube.output == -1) + fatal("output_phase_setup: must have an output"); + + F = PLA->F; + D = PLA->D; + R = PLA->R; + first_part = cube.first_part[cube.output] + first_output; + last_part = cube.last_part[cube.output]; + offset = cube.part_size[cube.output] - first_output; + + /* Change the output size, setup the cube structure */ + setdown_cube(); + cube.part_size[cube.output] += offset; + cube_setup(); + + /* Create a mask to select that part of the cube which isn't changing */ + mask = set_save(cube.fullset); + for(i = first_part; i < cube.size; i++) + set_remove(mask, i); + mask1 = set_save(mask); + for(i = cube.first_part[cube.output]; i < first_part; i++) { + set_remove(mask1, i); + } + + PLA->F = new_cover(F->count + R->count); + PLA->R = new_cover(F->count + R->count); + PLA->D = new_cover(D->count); + + foreach_set(F, last, p) { + pf = GETSET(PLA->F, (PLA->F)->count++); + pr = GETSET(PLA->R, (PLA->R)->count++); + INLINEset_and(pf, mask, p); + INLINEset_and(pr, mask1, p); + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + set_insert(pf, i); + save = FALSE; + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + save = TRUE, set_insert(pr, i+offset); + if (! save) PLA->R->count--; + } + + foreach_set(R, last, p) { + pf = GETSET(PLA->F, (PLA->F)->count++); + pr = GETSET(PLA->R, (PLA->R)->count++); + INLINEset_and(pf, mask1, p); + INLINEset_and(pr, mask, p); + save = FALSE; + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + save = TRUE, set_insert(pf, i+offset); + if (! save) PLA->F->count--; + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) + set_insert(pr, i); + } + + foreach_set(D, last, p) { + pf = GETSET(PLA->D, (PLA->D)->count++); + INLINEset_and(pf, mask, p); + for(i = first_part; i <= last_part; i++) + if (is_in_set(p, i)) { + set_insert(pf, i); + set_insert(pf, i+offset); + } + } + + free_cover(F); + free_cover(D); + free_cover(R); + set_free(mask); + set_free(mask1); +} + +/* + * set_phase -- given a "cube" which describes which phases of the output + * are to be implemented, compute the appropriate on-set and off-set + */ +pPLA set_phase(PLA) +INOUT pPLA PLA; +{ + pcover F1, R1; + register pcube last, p, outmask; + register pcube temp=cube.temp[0], phase=PLA->phase, phase1=cube.temp[1]; + + outmask = cube.var_mask[cube.num_vars - 1]; + set_diff(phase1, outmask, phase); + set_or(phase1, set_diff(temp, cube.fullset, outmask), phase1); + F1 = new_cover((PLA->F)->count + (PLA->R)->count); + R1 = new_cover((PLA->F)->count + (PLA->R)->count); + + foreach_set(PLA->F, last, p) { + if (! setp_disjoint(set_and(temp, p, phase), outmask)) + set_copy(GETSET(F1, F1->count++), temp); + if (! setp_disjoint(set_and(temp, p, phase1), outmask)) + set_copy(GETSET(R1, R1->count++), temp); + } + foreach_set(PLA->R, last, p) { + if (! setp_disjoint(set_and(temp, p, phase), outmask)) + set_copy(GETSET(R1, R1->count++), temp); + if (! setp_disjoint(set_and(temp, p, phase1), outmask)) + set_copy(GETSET(F1, F1->count++), temp); + } + free_cover(PLA->F); + free_cover(PLA->R); + PLA->F = F1; + PLA->R = R1; + return PLA; +} + +#define POW2(x) (1 << (x)) + +void opoall(PLA, first_output, last_output, opo_strategy) +pPLA PLA; +int first_output, last_output; +int opo_strategy; +{ + pcover F, D, R, best_F, best_D, best_R; + int i, j, ind, num; + pcube bestphase; + + opo_exact = opo_strategy; + + if (PLA->phase != NULL) { + set_free(PLA->phase); + } + + bestphase = set_save(cube.fullset); + best_F = sf_save(PLA->F); + best_D = sf_save(PLA->D); + best_R = sf_save(PLA->R); + + for(i = 0; i < POW2(last_output - first_output + 1); i++) { + + /* save the initial PLA covers */ + F = sf_save(PLA->F); + D = sf_save(PLA->D); + R = sf_save(PLA->R); + + /* compute the phase cube for this iteration */ + PLA->phase = set_save(cube.fullset); + num = i; + for(j = last_output; j >= first_output; j--) { + if (num % 2 == 0) { + ind = cube.first_part[cube.output] + j; + set_remove(PLA->phase, ind); + } + num /= 2; + } + + /* set the phase and minimize */ + (void) set_phase(PLA); + printf("# phase is %s\n", pc1(PLA->phase)); + summary = TRUE; + minimize(PLA); + + /* see if this is the best so far */ + if (PLA->F->count < best_F->count) { + /* save new best solution */ + set_copy(bestphase, PLA->phase); + sf_free(best_F); + sf_free(best_D); + sf_free(best_R); + best_F = PLA->F; + best_D = PLA->D; + best_R = PLA->R; + } else { + /* throw away the solution */ + free_cover(PLA->F); + free_cover(PLA->D); + free_cover(PLA->R); + } + set_free(PLA->phase); + + /* restore the initial PLA covers */ + PLA->F = F; + PLA->D = D; + PLA->R = R; + } + + /* one more minimization to restore the best answer */ + PLA->phase = bestphase; + sf_free(PLA->F); + sf_free(PLA->D); + sf_free(PLA->R); + PLA->F = best_F; + PLA->D = best_D; + PLA->R = best_R; +} + +static void minimize(PLA) +pPLA PLA; +{ + if (opo_exact) { + EXEC_S(PLA->F = minimize_exact(PLA->F,PLA->D,PLA->R,1), "EXACT", PLA->F); + } else { + EXEC_S(PLA->F = espresso(PLA->F, PLA->D, PLA->R), "ESPRESSO ",PLA->F); + } +} diff --git a/benchmarks/benchmarks/espresso/pair.c b/benchmarks/benchmarks/espresso/pair.c new file mode 100644 index 0000000..50e86aa --- /dev/null +++ b/benchmarks/benchmarks/espresso/pair.c @@ -0,0 +1,666 @@ +#include "espresso.h" + +void set_pair(PLA) +pPLA PLA; +{ + set_pair1(PLA, TRUE); +} + +void set_pair1(PLA, adjust_labels) +pPLA PLA; +bool adjust_labels; +{ + int i, var, *paired, newvar; + int old_num_vars, old_num_binary_vars, old_size, old_mv_start; + int *new_part_size, new_num_vars, new_num_binary_vars, new_mv_start; + ppair pair = PLA->pair; + char scratch[1000], **oldlabel, *var1, *var1bar, *var2, *var2bar; + + if (adjust_labels) + makeup_labels(PLA); + + /* Check the pair structure for valid entries and see which binary + variables are left unpaired + */ + paired = ALLOC(bool, cube.num_binary_vars); + for(var = 0; var < cube.num_binary_vars; var++) + paired[var] = FALSE; + for(i = 0; i < pair->cnt; i++) + if ((pair->var1[i] > 0 && pair->var1[i] <= cube.num_binary_vars) && + (pair->var2[i] > 0 && pair->var2[i] <= cube.num_binary_vars)) { + paired[pair->var1[i]-1] = TRUE; + paired[pair->var2[i]-1] = TRUE; + } else + fatal("can only pair binary-valued variables"); + + PLA->F = delvar(pairvar(PLA->F, pair), paired); + PLA->R = delvar(pairvar(PLA->R, pair), paired); + PLA->D = delvar(pairvar(PLA->D, pair), paired); + + /* Now painfully adjust the cube size */ + old_size = cube.size; + old_num_vars = cube.num_vars; + old_num_binary_vars = cube.num_binary_vars; + old_mv_start = cube.first_part[cube.num_binary_vars]; + /* Create the new cube.part_size vector and setup the cube structure */ + new_num_binary_vars = 0; + for(var = 0; var < old_num_binary_vars; var++) + new_num_binary_vars += (paired[var] == FALSE); + new_num_vars = new_num_binary_vars + pair->cnt; + new_num_vars += old_num_vars - old_num_binary_vars; + new_part_size = ALLOC(int, new_num_vars); + for(var = 0; var < pair->cnt; var++) + new_part_size[new_num_binary_vars + var] = 4; + for(var = 0; var < old_num_vars - old_num_binary_vars; var++) + new_part_size[new_num_binary_vars + pair->cnt + var] = + cube.part_size[old_num_binary_vars + var]; + setdown_cube(); + FREE(cube.part_size); + cube.num_vars = new_num_vars; + cube.num_binary_vars = new_num_binary_vars; + cube.part_size = new_part_size; + cube_setup(); + + /* hack with the labels to get them correct */ + if (adjust_labels) { + oldlabel = PLA->label; + PLA->label = ALLOC(char *, cube.size); + for(var = 0; var < pair->cnt; var++) { + newvar = cube.num_binary_vars*2 + var*4; + var1 = oldlabel[ (pair->var1[var]-1) * 2 + 1]; + var2 = oldlabel[ (pair->var2[var]-1) * 2 + 1]; + var1bar = oldlabel[ (pair->var1[var]-1) * 2]; + var2bar = oldlabel[ (pair->var2[var]-1) * 2]; + (void) sprintf(scratch, "%s+%s", var1bar, var2bar); + PLA->label[newvar] = util_strsav(scratch); + (void) sprintf(scratch, "%s+%s", var1bar, var2); + PLA->label[newvar+1] = util_strsav(scratch); + (void) sprintf(scratch, "%s+%s", var1, var2bar); + PLA->label[newvar+2] = util_strsav(scratch); + (void) sprintf(scratch, "%s+%s", var1, var2); + PLA->label[newvar+3] = util_strsav(scratch); + } + /* Copy the old labels for the unpaired binary vars */ + i = 0; + for(var = 0; var < old_num_binary_vars; var++) { + if (paired[var] == FALSE) { + PLA->label[2*i] = oldlabel[2*var]; + PLA->label[2*i+1] = oldlabel[2*var+1]; + oldlabel[2*var] = oldlabel[2*var+1] = (char *) NULL; + i++; + } + } + /* Copy the old labels for the remaining unpaired vars */ + new_mv_start = cube.num_binary_vars*2 + pair->cnt*4; + for(i = old_mv_start; i < old_size; i++) { + PLA->label[new_mv_start + i - old_mv_start] = oldlabel[i]; + oldlabel[i] = (char *) NULL; + } + /* free remaining entries in oldlabel */ + for(i = 0; i < old_size; i++) + if (oldlabel[i] != (char *) NULL) + FREE(oldlabel[i]); + FREE(oldlabel); + } + + /* the paired variables should not be sparse (cf. mv_reduce/raise_in)*/ + for(var = 0; var < pair->cnt; var++) + cube.sparse[cube.num_binary_vars + var] = 0; + FREE(paired); +} + +pcover pairvar(A, pair) +pcover A; +ppair pair; +{ + register pcube last, p; + register int val, p1, p2, b1, b0; + int insert_col, pairnum; + + insert_col = cube.first_part[cube.num_vars - 1]; + + /* stretch the cover matrix to make room for the paired variables */ + A = sf_delcol(A, insert_col, -4*pair->cnt); + + /* compute the paired values */ + foreach_set(A, last, p) { + for(pairnum = 0; pairnum < pair->cnt; pairnum++) { + p1 = cube.first_part[pair->var1[pairnum] - 1]; + p2 = cube.first_part[pair->var2[pairnum] - 1]; + b1 = is_in_set(p, p2+1); + b0 = is_in_set(p, p2); + val = insert_col + pairnum * 4; + if (/* a0 */ is_in_set(p, p1)) { + if (b0) + set_insert(p, val + 3); + if (b1) + set_insert(p, val + 2); + } + if (/* a1 */ is_in_set(p, p1+1)) { + if (b0) + set_insert(p, val + 1); + if (b1) + set_insert(p, val); + } + } + } + return A; +} + + +/* delvar -- delete variables from A, minimize the number of column shifts */ +pcover delvar(A, paired) +pcover A; +bool paired[]; +{ + bool run; + int first_run, run_length, var, offset = 0; + + run = FALSE; run_length = 0; + for(var = 0; var < cube.num_binary_vars; var++) + if (paired[var]) + if (run) + run_length += cube.part_size[var]; + else { + run = TRUE; + first_run = cube.first_part[var]; + run_length = cube.part_size[var]; + } + else + if (run) { + A = sf_delcol(A, first_run-offset, run_length); + run = FALSE; + offset += run_length; + } + if (run) + A = sf_delcol(A, first_run-offset, run_length); + return A; +} + +/* + find_optimal_pairing -- find which binary variables should be paired + to maximally reduce the number of terms + + This is essentially the technique outlined by T. Sasao in the + Trans. on Comp., Oct 1984. We estimate the cost of pairing each + pair individually using 1 of 4 strategies: (1) algebraic division + of F by the pair (exactly T. Sasao technique); (2) strong division + of F by the paired variables (using REDUCE/EXPAND/ IRREDUNDANT from + espresso); (3) full minimization using espresso; (4) exact + minimization. These are in order of both increasing accuracy and + increasing difficulty (!) + + Once the n squared pairs have been evaluated, T. Sasao proposes a + graph covering of nodes by disjoint edges. For now, I solve this + problem exhaustively (complexity = (n-1)*(n-3)*...*3*1 for n + variables when n is even). Note that solving this problem exactly + is the same as evaluating the cost function for all possible + pairings. + + n pairs + + 1, 2 1 + 3, 4 3 + 5, 6 15 + 7, 8 105 + 9,10 945 + 11,12 10,395 + 13,14 135,135 + 15,16 2,027,025 + 17,18 34,459,425 + 19,20 654,729,075 +*/ +void find_optimal_pairing(PLA, strategy) +pPLA PLA; +int strategy; +{ + int i, j, **cost_array; + + cost_array = find_pairing_cost(PLA, strategy); + + if (summary) { + printf(" "); + for(i = 0; i < cube.num_binary_vars; i++) + printf("%3d ", i+1); + printf("\n"); + for(i = 0; i < cube.num_binary_vars; i++) { + printf("%3d ", i+1); + for(j = 0; j < cube.num_binary_vars; j++) + printf("%3d ", cost_array[i][j]); + printf("\n"); + } + } + + if (cube.num_binary_vars <= 14) { + PLA->pair = pair_best_cost(cost_array); + } else { + (void) greedy_best_cost(cost_array, &(PLA->pair)); + } + printf("# "); + print_pair(PLA->pair); + + for(i = 0; i < cube.num_binary_vars; i++) + FREE(cost_array[i]); + FREE(cost_array); + + set_pair(PLA); + EXEC_S(PLA->F=espresso(PLA->F,PLA->D,PLA->R),"ESPRESSO ",PLA->F); +} + +int **find_pairing_cost(PLA, strategy) +pPLA PLA; +int strategy; +{ + int var1, var2, **cost_array; + int i, j, xnum_binary_vars, xnum_vars, *xpart_size, cost; + pcover T, Fsave, Dsave, Rsave; + pset mask; +/* char *s;*/ + + /* data is returned in the cost array */ + cost_array = ALLOC(int *, cube.num_binary_vars); + for(i = 0; i < cube.num_binary_vars; i++) + cost_array[i] = ALLOC(int, cube.num_binary_vars); + for(i = 0; i < cube.num_binary_vars; i++) + for(j = 0; j < cube.num_binary_vars; j++) + cost_array[i][j] = 0; + + /* Setup the pair structure for pairing variables together */ + PLA->pair = pair_new(1); + PLA->pair->cnt = 1; + + for(var1 = 0; var1 < cube.num_binary_vars-1; var1++) { + for(var2 = var1+1; var2 < cube.num_binary_vars; var2++) { + /* if anything but simple strategy, perform setup */ + if (strategy > 0) { + /* save the original covers */ + Fsave = sf_save(PLA->F); + Dsave = sf_save(PLA->D); + Rsave = sf_save(PLA->R); + + /* save the original cube structure */ + xnum_binary_vars = cube.num_binary_vars; + xnum_vars = cube.num_vars; + xpart_size = ALLOC(int, cube.num_vars); + for(i = 0; i < cube.num_vars; i++) + xpart_size[i] = cube.part_size[i]; + + /* pair two variables together */ + PLA->pair->var1[0] = var1 + 1; + PLA->pair->var2[0] = var2 + 1; + set_pair1(PLA, /* adjust_labels */ FALSE); + } + + + /* decide how to best estimate worth of this pairing */ + switch(strategy) { + case 3: + /*s = "exact minimization";*/ + PLA->F = minimize_exact(PLA->F, PLA->D, PLA->R, 1); + cost = Fsave->count - PLA->F->count; + break; + case 2: + /*s = "full minimization";*/ + PLA->F = espresso(PLA->F, PLA->D, PLA->R); + cost = Fsave->count - PLA->F->count; + break; + case 1: + /*s = "strong division";*/ + PLA->F = reduce(PLA->F, PLA->D); + PLA->F = expand(PLA->F, PLA->R, FALSE); + PLA->F = irredundant(PLA->F, PLA->D); + cost = Fsave->count - PLA->F->count; + break; + case 0: + /*s = "weak division";*/ + mask = new_cube(); + set_or(mask, cube.var_mask[var1], cube.var_mask[var2]); + T = dist_merge(sf_save(PLA->F), mask); + cost = PLA->F->count - T->count; + sf_free(T); + set_free(mask); + } + + cost_array[var1][var2] = cost; + + if (strategy > 0) { + /* restore the original cube structure -- free the new ones */ + setdown_cube(); + FREE(cube.part_size); + cube.num_binary_vars = xnum_binary_vars; + cube.num_vars = xnum_vars; + cube.part_size = xpart_size; + cube_setup(); + + /* restore the original cover(s) -- free the new ones */ + sf_free(PLA->F); + sf_free(PLA->D); + sf_free(PLA->R); + PLA->F = Fsave; + PLA->D = Dsave; + PLA->R = Rsave; + } + } + } + + pair_free(PLA->pair); + PLA->pair = NULL; + return cost_array; +} + +static int best_cost; +static int **cost_array; +static ppair best_pair; +static pset best_phase; +static pPLA global_PLA; +static pcover best_F, best_D, best_R; +static int pair_minim_strategy; + + +print_pair(pair) +ppair pair; +{ + int i; + + printf("pair is"); + for(i = 0; i < pair->cnt; i++) + printf (" (%d %d)", pair->var1[i], pair->var2[i]); + printf("\n"); +} + + +int greedy_best_cost(cost_array_local, pair_p) +int **cost_array_local; +ppair *pair_p; +{ + int i, j, besti, bestj, maxcost, total_cost; + pset cand; + ppair pair; + + pair = pair_new(cube.num_binary_vars); + cand = set_full(cube.num_binary_vars); + total_cost = 0; + + while (set_ord(cand) >= 2) { + maxcost = -1; + for(i = 0; i < cube.num_binary_vars; i++) { + if (is_in_set(cand, i)) { + for(j = i+1; j < cube.num_binary_vars; j++) { + if (is_in_set(cand, j)) { + if (cost_array_local[i][j] > maxcost) { + maxcost = cost_array_local[i][j]; + besti = i; + bestj = j; + } + } + } + } + } + pair->var1[pair->cnt] = besti+1; + pair->var2[pair->cnt] = bestj+1; + pair->cnt++; + set_remove(cand, besti); + set_remove(cand, bestj); + total_cost += maxcost; + } + set_free(cand); + *pair_p = pair; + return total_cost; +} + + +ppair pair_best_cost(cost_array_local) +int **cost_array_local; +{ + ppair pair; + pset candidate; + + best_cost = -1; + best_pair = NULL; + cost_array = cost_array_local; + + pair = pair_new(cube.num_binary_vars); + candidate = set_full(cube.num_binary_vars); + generate_all_pairs(pair, cube.num_binary_vars, candidate, find_best_cost); + pair_free(pair); + set_free(candidate); + return best_pair; +} + + +int find_best_cost(pair) +register ppair pair; +{ + register int i, cost; + + cost = 0; + for(i = 0; i < pair->cnt; i++) + cost += cost_array[pair->var1[i]-1][pair->var2[i]-1]; + if (cost > best_cost) { + best_cost = cost; + best_pair = pair_save(pair, pair->cnt); + } + if ((debug & MINCOV) && trace) { + printf("cost is %d ", cost); + print_pair(pair); + } +} + +/* + pair_all: brute-force approach to try all possible pairings + + pair_strategy is: + 2) for espresso + 3) for minimize_exact + 4) for phase assignment +*/ + +pair_all(PLA, pair_strategy) +pPLA PLA; +int pair_strategy; +{ + ppair pair; + pset candidate; + + global_PLA = PLA; + pair_minim_strategy = pair_strategy; + best_cost = PLA->F->count + 1; + best_pair = NULL; + best_phase = NULL; + best_F = best_D = best_R = NULL; + pair = pair_new(cube.num_binary_vars); + candidate = set_fill(set_new(cube.num_binary_vars), cube.num_binary_vars); + + generate_all_pairs(pair, cube.num_binary_vars, candidate, minimize_pair); + + pair_free(pair); + set_free(candidate); + + PLA->pair = best_pair; + PLA->phase = best_phase; +/* not really necessary + if (phase != NULL) + (void) set_phase(PLA->phase); +*/ + set_pair(PLA); + printf("# "); + print_pair(PLA->pair); + + sf_free(PLA->F); + sf_free(PLA->D); + sf_free(PLA->R); + PLA->F = best_F; + PLA->D = best_D; + PLA->R = best_R; +} + + +/* + * minimize_pair -- called as each pair is generated + */ +int minimize_pair(pair) +ppair pair; +{ + pcover Fsave, Dsave, Rsave; + int i, xnum_binary_vars, xnum_vars, *xpart_size; + + /* save the original covers */ + Fsave = sf_save(global_PLA->F); + Dsave = sf_save(global_PLA->D); + Rsave = sf_save(global_PLA->R); + + /* save the original cube structure */ + xnum_binary_vars = cube.num_binary_vars; + xnum_vars = cube.num_vars; + xpart_size = ALLOC(int, cube.num_vars); + for(i = 0; i < cube.num_vars; i++) + xpart_size[i] = cube.part_size[i]; + + /* setup the paired variables */ + global_PLA->pair = pair; + set_pair1(global_PLA, /* adjust_labels */ FALSE); + + /* call the minimizer */ + if (summary) + print_pair(pair); + switch(pair_minim_strategy) { + case 2: + EXEC_S(phase_assignment(global_PLA,0), "OPO ", global_PLA->F); + if (summary) + printf("# phase is %s\n", pc1(global_PLA->phase)); + break; + case 1: + EXEC_S(global_PLA->F = minimize_exact(global_PLA->F, global_PLA->D, + global_PLA->R, 1), "EXACT ", global_PLA->F); + break; + case 0: + EXEC_S(global_PLA->F = espresso(global_PLA->F, global_PLA->D, + global_PLA->R), "ESPRESSO ", global_PLA->F); + break; + default: + break; + } + + /* see if we have a new best solution */ + if (global_PLA->F->count < best_cost) { + best_cost = global_PLA->F->count; + best_pair = pair_save(pair, pair->cnt); + best_phase = global_PLA->phase!=NULL?set_save(global_PLA->phase):NULL; + if (best_F != NULL) sf_free(best_F); + if (best_D != NULL) sf_free(best_D); + if (best_R != NULL) sf_free(best_R); + best_F = sf_save(global_PLA->F); + best_D = sf_save(global_PLA->D); + best_R = sf_save(global_PLA->R); + } + + /* restore the original cube structure -- free the new ones */ + setdown_cube(); + FREE(cube.part_size); + cube.num_binary_vars = xnum_binary_vars; + cube.num_vars = xnum_vars; + cube.part_size = xpart_size; + cube_setup(); + + /* restore the original cover(s) -- free the new ones */ + sf_free(global_PLA->F); + sf_free(global_PLA->D); + sf_free(global_PLA->R); + global_PLA->F = Fsave; + global_PLA->D = Dsave; + global_PLA->R = Rsave; + global_PLA->pair = NULL; + global_PLA->phase = NULL; +} + +generate_all_pairs(pair, n, candidate, action) +ppair pair; +int n; +pset candidate; +int (*action)(); +{ + int i, j; + pset recur_candidate; + ppair recur_pair; + + if (set_ord(candidate) < 2) { + (*action)(pair); + return 0; + } + + recur_pair = pair_save(pair, n); + recur_candidate = set_save(candidate); + + /* Find first variable still in the candidate set */ + for(i = 0; i < n; i++) + if (is_in_set(candidate, i)) + break; + + /* Try all pairs of i with other variables */ + for(j = i+1; j < n; j++) + if (is_in_set(candidate, j)) { + /* pair (i j) -- remove from candidate set for future pairings */ + set_remove(recur_candidate, i); + set_remove(recur_candidate, j); + + /* add to the pair array */ + recur_pair->var1[recur_pair->cnt] = i+1; + recur_pair->var2[recur_pair->cnt] = j+1; + recur_pair->cnt++; + + /* recur looking for the end ... */ + generate_all_pairs(recur_pair, n, recur_candidate, action); + + /* now break this pair, and restore candidate set */ + recur_pair->cnt--; + set_insert(recur_candidate, i); + set_insert(recur_candidate, j); + } + + /* if odd, generate all pairs which do NOT include i */ + if ((set_ord(candidate) % 2) == 1) { + set_remove(recur_candidate, i); + generate_all_pairs(recur_pair, n, recur_candidate, action); + } + + pair_free(recur_pair); + set_free(recur_candidate); +} + +ppair pair_new(n) +register int n; +{ + register ppair pair1; + + pair1 = ALLOC(pair_t, 1); + pair1->cnt = 0; + pair1->var1 = ALLOC(int, n); + pair1->var2 = ALLOC(int, n); + return pair1; +} + + +ppair pair_save(pair, n) +register ppair pair; +register int n; +{ + register int k; + register ppair pair1; + + pair1 = pair_new(n); + pair1->cnt = pair->cnt; + for(k = 0; k < pair->cnt; k++) { + pair1->var1[k] = pair->var1[k]; + pair1->var2[k] = pair->var2[k]; + } + return pair1; +} + + +int pair_free(pair) +register ppair pair; +{ + FREE(pair->var1); + FREE(pair->var2); + FREE(pair); +} diff --git a/benchmarks/benchmarks/espresso/part.c b/benchmarks/benchmarks/espresso/part.c new file mode 100644 index 0000000..c2c2407 --- /dev/null +++ b/benchmarks/benchmarks/espresso/part.c @@ -0,0 +1,114 @@ +#include "espresso.h" +#include "mincov_int.h" + +static int visit_col(); + +static void +copy_row(A, prow) +register sm_matrix *A; +register sm_row *prow; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_insert(A, p->row_num, p->col_num); + } +} + + +static int +visit_row(A, prow, rows_visited, cols_visited) +sm_matrix *A; +sm_row *prow; +int *rows_visited; +int *cols_visited; +{ + sm_element *p; + sm_col *pcol; + + if (! prow->flag) { + prow->flag = 1; + (*rows_visited)++; + if (*rows_visited == A->nrows) { + return 1; + } + for(p = prow->first_col; p != 0; p = p->next_col) { + pcol = sm_get_col(A, p->col_num); + if (! pcol->flag) { + if (visit_col(A, pcol, rows_visited, cols_visited)) { + return 1; + } + } + } + } + return 0; +} + + +static int +visit_col(A, pcol, rows_visited, cols_visited) +sm_matrix *A; +sm_col *pcol; +int *rows_visited; +int *cols_visited; +{ + sm_element *p; + sm_row *prow; + + if (! pcol->flag) { + pcol->flag = 1; + (*cols_visited)++; + if (*cols_visited == A->ncols) { + return 1; + } + for(p = pcol->first_row; p != 0; p = p->next_row) { + prow = sm_get_row(A, p->row_num); + if (! prow->flag) { + if (visit_row(A, prow, rows_visited, cols_visited)) { + return 1; + } + } + } + } + return 0; +} + +int +sm_block_partition(A, L, R) +sm_matrix *A; +sm_matrix **L, **R; +{ + int cols_visited, rows_visited; + register sm_row *prow; + register sm_col *pcol; + + /* Avoid the trivial case */ + if (A->nrows == 0) { + return 0; + } + + /* Reset the visited flags for each row and column */ + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + prow->flag = 0; + } + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) { + pcol->flag = 0; + } + + cols_visited = rows_visited = 0; + if (visit_row(A, A->first_row, &rows_visited, &cols_visited)) { + /* we found all of the rows */ + return 0; + } else { + *L = sm_alloc(); + *R = sm_alloc(); + for(prow = A->first_row; prow != 0; prow = prow->next_row) { + if (prow->flag) { + copy_row(*L, prow); + } else { + copy_row(*R, prow); + } + } + return 1; + } +} diff --git a/benchmarks/benchmarks/espresso/port.h b/benchmarks/benchmarks/espresso/port.h new file mode 100644 index 0000000..d84a1b5 --- /dev/null +++ b/benchmarks/benchmarks/espresso/port.h @@ -0,0 +1,263 @@ +#ifndef PORT_H +#define PORT_H + +#ifdef _WIN32 +#include +#include +#endif + +#ifndef NULL +#define NULL 0 +#endif /* NULL */ + +#ifndef _WIN32 + +#ifdef SABER +#define volatile +#endif + +#ifdef _IBMR2 +#define _BSD +#ifndef _POSIX_SOURCE +#define _POSIX_SOURCE /* Argh! IBM strikes again */ +#endif +#ifndef _ALL_SOURCE +#define _ALL_SOURCE /* Argh! IBM strikes again */ +#endif +#ifndef _ANSI_C_SOURCE +#define _ANSI_C_SOURCE /* Argh! IBM strikes again */ +#endif +#endif + +/* + * int32 should be defined as the most economical sized integer capable of + * holding a 32 bit quantity + * int16 should be similarly defined + */ + +/* XXX hack */ +#ifndef MACHDEP_INCLUDED +#define MACHDEP_INCLUDED +#ifdef vax +typedef int int32; +typedef short int16; +#else + /* Ansi-C promises that these definitions should always work */ +typedef long int32; +typedef int int16; +#endif /* vax */ +#endif /* MACHDEP_INCLUDED */ + + +#ifndef __STDC__ +#ifndef __DATE__ +#ifdef CUR_DATE +#define __DATE__ CUR_DATE +#else +#define __DATE__ "unknown-date" +#endif /* CUR_DATE */ +#endif /* __DATE__ */ + +#ifndef __TIME__ +#ifdef CUR_TIME +#define __TIME__ CUR_TIME +#else +#define __TIME__ "unknown-time" +#endif /* CUR_TIME */ +#endif /* __TIME__ */ +#endif /* __STDC__ */ + +#ifdef sun386 +#define PORTAR +#endif + +#include +#include +#include +#undef HUGE +#include +#include + +#if defined(ultrix) /* { */ +#if defined(_SIZE_T_) /* { */ +#define ultrix4 +#else /* } else { */ +#if defined(SIGLOST) /* { */ +#define ultrix3 +#else /* } else { */ +#define ultrix2 +#endif /* } */ +#endif /* } */ +#endif /* } */ + +#if defined(ultrix3) && defined(mips) +extern double rint(); +extern double trunc(); +#endif + +#if defined(sun) && defined(FD_SETSIZE) +#define sunos4 +#else +#define sunos3 +#endif + +#if defined(sequent) || defined(news800) +#define LACK_SYS5 +#endif + +#if defined(ultrix3) || defined(sunos4) || defined(_IBMR2) +#define SIGNAL_FN void +#else +/* sequent, ultrix2, 4.3BSD (vax, hp), sunos3 */ +#define SIGNAL_FN int +#endif + +/* Some systems have 'fixed' certain functions which used to be int */ +#if defined(ultrix) || defined(SABER) || defined(hpux) || defined(aiws) || defined(apollo) || defined(__STDC__) +#define VOID_HACK void +#else +#define VOID_HACK int +#endif + +/* + * CHARBITS should be defined only if the compiler lacks "unsigned char". + * It should be a mask, e.g. 0377 for an 8-bit machine. + */ + +#ifndef CHARBITS +# define UNSCHAR(c) ((unsigned char)(c)) +#else +# define UNSCHAR(c) ((c)&CHARBITS) +#endif + +#define SIZET int + +#ifdef __STDC__ +#define CONST const +#define VOIDSTAR void * +#else +#define CONST +#define VOIDSTAR char * +#endif /* __STDC__ */ + + +/* Some machines fail to define some functions in stdio.h */ +#if !defined(__STDC__) && !defined(sprite) +extern FILE *popen(), *tmpfile(); +extern int pclose(); +#ifndef clearerr /* is a macro on many machines, but not all */ +extern VOID_HACK clearerr(); +#endif /* clearerr */ +#ifndef rewind +extern VOID_HACK rewind(); +#endif /* rewind */ +#endif /* __STDC__ */ + + +/* most machines don't give us a header file for these */ +#if defined(__STDC__) || defined(sprite) +#include +#else +#ifdef hpux +extern int abort(); +extern void free(), exit(), perror(); +#else +extern VOID_HACK abort(), free(), exit(), perror(); +#endif /* hpux */ +extern char *getenv(); +#ifdef ultrix4 +extern void *malloc(), *realloc(), *calloc(); +#else +extern char *malloc(), *realloc(), *calloc(); +#endif +#if defined(aiws) || defined(hpux) +extern int sprintf(); +#else +extern char *sprintf(); +#endif +extern int system(); +extern double atof(); +extern long atol(); +extern int sscanf(); +#endif /* __STDC__ */ + + +/* some call it strings.h, some call it string.h; others, also have memory.h */ +#if defined(__STDC__) || defined(sprite) +#include +#else +/* ANSI C string.h -- 1/11/88 Draft Standard */ +#if defined(ultrix4) || defined(hpux) +#include +#else +extern char *strcpy(), *strncpy(), *strcat(), *strncat(), *strerror(); +extern char *strpbrk(), *strtok(), *strchr(), *strrchr(), *strstr(); +extern int strcoll(), strxfrm(), strncmp(), strlen(), strspn(), strcspn(); +extern char *memmove(), *memccpy(), *memchr(), *memcpy(), *memset(); +extern int memcmp(), strcmp(); +#endif /* ultrix4 */ +#endif /* __STDC__ */ + +#ifdef lint +#undef putc /* correct lint '_flsbuf' bug */ +#endif /* lint */ + +/* a few extras */ +#if defined(hpux) +extern VOID_HACK srand(); +extern int rand(); +#define random() rand() +#define srandom(a) srand(a) +#define bzero(a,b) memset(a, 0, b) +#else +extern VOID_HACK srandom(); +extern long random(); +#endif + +/* +** _std_h is defined in /usr/local/lib/g++-include/std.h +*/ +#if ! defined(_std_h) +#if defined(ultrix3) || defined(ultrix4) || defined(hpux) +extern unsigned sleep(); +#else +extern VOID_HACK sleep(); +#endif +#endif /* _std_h */ +/* assertion macro */ + +#ifndef assert +#if defined(__STDC__) || defined(sprite) +#include +#else +#ifndef NDEBUG +#define assert(ex) {\ + if (! (ex)) {\ + (void) fprintf(stderr, "Assertion failed: file %s, line %d\n",\ + __FILE__, __LINE__);\ + (void) fflush(stdout);\ + abort();\ + }\ +} +#else +#define assert(ex) {;} +#endif +#endif +#endif + +/* handle the various limits */ +#if defined(__STDC__) || defined(POSIX) +#include +#else +#define USHRT_MAX (~ (unsigned short int) 0) +#define UINT_MAX (~ (unsigned int) 0) +#define ULONG_MAX (~ (unsigned long int) 0) +#define SHRT_MAX ((short int) (USHRT_MAX >> 1)) +#define INT_MAX ((int) (UINT_MAX >> 1)) +#define LONG_MAX ((long int) (ULONG_MAX >> 1)) +#endif + +#endif + +#endif /* PORT_H */ + diff --git a/benchmarks/benchmarks/espresso/primes.c b/benchmarks/benchmarks/espresso/primes.c new file mode 100644 index 0000000..7386784 --- /dev/null +++ b/benchmarks/benchmarks/espresso/primes.c @@ -0,0 +1,161 @@ +#include "espresso.h" + +static bool primes_consensus_special_cases(); +static pcover primes_consensus_merge(); +static pcover and_with_cofactor(); + + +/* primes_consensus -- generate primes using consensus */ +pcover primes_consensus(T) +pcube *T; /* T will be disposed of */ +{ + register pcube cl, cr; + register int best; + pcover Tnew, Tl, Tr; + + if (primes_consensus_special_cases(T, &Tnew) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, COMPL); + + Tl = primes_consensus(scofactor(T, cl, best)); + Tr = primes_consensus(scofactor(T, cr, best)); + Tnew = primes_consensus_merge(Tl, Tr, cl, cr); + + free_cube(cl); + free_cube(cr); + free_cubelist(T); + } + + return Tnew; +} + +static bool +primes_consensus_special_cases(T, Tnew) +pcube *T; /* will be disposed if answer is determined */ +pcover *Tnew; /* returned only if answer determined */ +{ + register pcube *T1, p, ceil, cof=T[0]; + pcube last; + pcover A; + + /* Check for no cubes in the cover */ + if (T[2] == NULL) { + *Tnew = new_cover(0); + free_cubelist(T); + return TRUE; + } + + /* Check for only a single cube in the cover */ + if (T[3] == NULL) { + *Tnew = sf_addset(new_cover(1), set_or(cof, cof, T[2])); + free_cubelist(T); + return TRUE; + } + + /* Check for a row of all 1's (implies function is a tautology) */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + } + } + + /* Check for a column of all 0's which can be factored out */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + p = new_cube(); + (void) set_diff(p, cube.fullset, ceil); + (void) set_or(cof, cof, p); + free_cube(p); + + A = primes_consensus(T); + foreach_set(A, last, p) { + INLINEset_and(p, p, ceil); + } + *Tnew = A; + set_free(ceil); + return TRUE; + } + set_free(ceil); + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If single active variable not factored out above, then tautology ! */ + if (cdata.vars_active == 1) { + *Tnew = sf_addset(new_cover(1), cube.fullset); + free_cubelist(T); + return TRUE; + + /* Check for unate cover */ + } else if (cdata.vars_unate == cdata.vars_active) { + A = cubeunlist(T); + *Tnew = sf_contain(A); + free_cubelist(T); + return TRUE; + + /* Not much we can do about it */ + } else { + return MAYBE; + } +} + +static pcover +primes_consensus_merge(Tl, Tr, cl, cr) +pcover Tl, Tr; +pcube cl, cr; +{ + register pcube pl, pr, lastl, lastr, pt; + pcover T, Tsave; + + Tl = and_with_cofactor(Tl, cl); + Tr = and_with_cofactor(Tr, cr); + + T = sf_new(500, Tl->sf_size); + pt = T->data; + Tsave = sf_contain(sf_join(Tl, Tr)); + + foreach_set(Tl, lastl, pl) { + foreach_set(Tr, lastr, pr) { + if (cdist01(pl, pr) == 1) { + consensus(pt, pl, pr); + if (++T->count >= T->capacity) { + Tsave = sf_union(Tsave, sf_contain(T)); + T = sf_new(500, Tl->sf_size); + pt = T->data; + } else { + pt += T->wsize; + } + } + } + } + free_cover(Tl); + free_cover(Tr); + + Tsave = sf_union(Tsave, sf_contain(T)); + return Tsave; +} + + +static pcover +and_with_cofactor(A, cof) +pset_family A; +register pset cof; +{ + register pset last, p; + + foreach_set(A, last, p) { + INLINEset_and(p, p, cof); + if (cdist(p, cube.fullset) > 0) { + RESET(p, ACTIVE); + } else { + SET(p, ACTIVE); + } + } + return sf_inactive(A); +} diff --git a/benchmarks/benchmarks/espresso/reduce.c b/benchmarks/benchmarks/espresso/reduce.c new file mode 100644 index 0000000..f818a2d --- /dev/null +++ b/benchmarks/benchmarks/espresso/reduce.c @@ -0,0 +1,249 @@ +/* + module: reduce.c + purpose: Perform the Espresso-II reduction step + + Reduction is a technique used to explore larger regions of the + optimization space. We replace each cube of F with a smaller + cube while still maintaining a cover of the same logic function. +*/ + +#include "espresso.h" + +static bool toggle = TRUE; + + +/* + reduce -- replace each cube in F with its reduction + + The reduction of a cube is the smallest cube contained in the cube + which can replace the cube in the original cover without changing + the cover. This is equivalent to the super cube of all of the + essential points in the cube. This can be computed directly. + + The problem is that the order in which the cubes are reduced can + greatly affect the final result. We alternate between two ordering + strategies: + + (1) Order the cubes in ascending order of distance from the + largest cube breaking ties by ordering cubes of equal distance + in descending order of size (sort_reduce) + + (2) Order the cubes in descending order of the inner-product of + the cube and the column sums (mini_sort) + + The real workhorse of this section is the routine SCCC which is + used to find the Smallest Cube Containing the Complement of a cover. + Reduction as proposed by Espresso-II takes a cube and computes its + maximal reduction as the intersection between the cube and the + smallest cube containing the complement of (F u D - {c}) cofactored + against c. + + As usual, the unate-recursive paradigm is used to compute SCCC. + The SCCC of a unate cover is trivial to compute, and thus we perform + Shannon Cofactor expansion attempting to drive the cover to be unate + as fast as possible. +*/ + +pcover reduce(F, D) +INOUT pcover F; +IN pcover D; +{ + register pcube last, p, cunder, *FD; + + /* Order the cubes */ + if (use_random_order) + F = random_order(F); + else { + F = toggle ? sort_reduce(F) : mini_sort(F, descend); + toggle = ! toggle; + } + + /* Try to reduce each cube */ + FD = cube2list(F, D); + foreach_set(F, last, p) { + cunder = reduce_cube(FD, p); /* reduce the cube */ + if (setp_equal(cunder, p)) { /* see if it actually did */ + SET(p, ACTIVE); /* cube remains active */ + SET(p, PRIME); /* cube remains prime ? */ + } else { + if (debug & REDUCE) { + printf("REDUCE: %s to %s %s\n", + pc1(p), pc2(cunder), print_time(ptime())); + } + set_copy(p, cunder); /* save reduced version */ + RESET(p, PRIME); /* cube is no longer prime */ + if (setp_empty(cunder)) + RESET(p, ACTIVE); /* if null, kill the cube */ + else + SET(p, ACTIVE); /* cube is active */ + } + free_cube(cunder); + } + free_cubelist(FD); + + /* Delete any cubes of F which reduced to the empty cube */ + return sf_inactive(F); +} + +/* reduce_cube -- find the maximal reduction of a cube */ +pcube reduce_cube(FD, p) +IN pcube *FD, p; +{ + pcube cunder; + + cunder = sccc(cofactor(FD, p)); + return set_and(cunder, cunder, p); +} + + +/* sccc -- find Smallest Cube Containing the Complement of a cover */ +pcube sccc(T) +INOUT pcube *T; /* T will be disposed of */ +{ + pcube r; + register pcube cl, cr; + register int best; + static int sccc_level = 0; + + if (debug & REDUCE1) { + debug_print(T, "SCCC", sccc_level++); + } + + if (sccc_special_cases(T, &r) == MAYBE) { + cl = new_cube(); + cr = new_cube(); + best = binate_split_select(T, cl, cr, REDUCE1); + r = sccc_merge(sccc(scofactor(T, cl, best)), + sccc(scofactor(T, cr, best)), cl, cr); + free_cubelist(T); + } + + if (debug & REDUCE1) + printf("SCCC[%d]: result is %s\n", --sccc_level, pc1(r)); + return r; +} + + +pcube sccc_merge(left, right, cl, cr) +INOUT register pcube left, right; /* will be disposed of ... */ +INOUT register pcube cl, cr; /* will be disposed of ... */ +{ + INLINEset_and(left, left, cl); + INLINEset_and(right, right, cr); + INLINEset_or(left, left, right); + free_cube(right); + free_cube(cl); + free_cube(cr); + return left; +} + + +/* + sccc_cube -- find the smallest cube containing the complement of a cube + + By DeMorgan's law and the fact that the smallest cube containing a + cover is the "or" of the positional cubes, it is simple to see that + the SCCC is the universe if the cube has more than two active + variables. If there is only a single active variable, then the + SCCC is merely the bitwise complement of the cube in that + variable. A last special case is no active variables, in which + case the SCCC is empty. + + This is "anded" with the incoming cube result. +*/ +pcube sccc_cube(result, p) +register pcube result, p; +{ + register pcube temp=cube.temp[0], mask; + int var; + + if ((var = cactive(p)) >= 0) { + mask = cube.var_mask[var]; + INLINEset_xor(temp, p, mask); + INLINEset_and(result, result, temp); + } + return result; +} + +/* + * sccc_special_cases -- check the special cases for sccc + */ + +bool sccc_special_cases(T, result) +INOUT pcube *T; /* will be disposed if answer is determined */ +OUT pcube *result; /* returned only if answer determined */ +{ + register pcube *T1, p, temp = cube.temp[1], ceil, cof = T[0]; + pcube *A, *B; + + /* empty cover => complement is universe => SCCC is universe */ + if (T[2] == NULL) { + *result = set_save(cube.fullset); + free_cubelist(T); + return TRUE; + } + + /* row of 1's => complement is empty => SCCC is empty */ + for(T1 = T+2; (p = *T1++) != NULL; ) { + if (full_row(p, cof)) { + *result = new_cube(); + free_cubelist(T); + return TRUE; + } + } + + /* Collect column counts, determine unate variables, etc. */ + massive_count(T); + + /* If cover is unate (or single cube), apply simple rules to find SCCCU */ + if (cdata.vars_unate == cdata.vars_active || T[3] == NULL) { + *result = set_save(cube.fullset); + for(T1 = T+2; (p = *T1++) != NULL; ) { + (void) sccc_cube(*result, set_or(temp, p, cof)); + } + free_cubelist(T); + return TRUE; + } + + /* Check for column of 0's (which can be easily factored( */ + ceil = set_save(cof); + for(T1 = T+2; (p = *T1++) != NULL; ) { + INLINEset_or(ceil, ceil, p); + } + if (! setp_equal(ceil, cube.fullset)) { + *result = sccc_cube(set_save(cube.fullset), ceil); + if (setp_equal(*result, cube.fullset)) { + free_cube(ceil); + } else { + *result = sccc_merge(sccc(cofactor(T,ceil)), + set_save(cube.fullset), ceil, *result); + } + free_cubelist(T); + return TRUE; + } + free_cube(ceil); + + /* Single active column at this point => tautology => SCCC is empty */ + if (cdata.vars_active == 1) { + *result = new_cube(); + free_cubelist(T); + return TRUE; + } + + /* Check for components */ + if (cdata.var_zeros[cdata.best] < CUBELISTSIZE(T)/2) { + if (cubelist_partition(T, &A, &B, debug & REDUCE1) == 0) { + return MAYBE; + } else { + free_cubelist(T); + *result = sccc(A); + ceil = sccc(B); + (void) set_and(*result, *result, ceil); + set_free(ceil); + return TRUE; + } + } + + /* Not much we can do about it */ + return MAYBE; +} diff --git a/benchmarks/benchmarks/espresso/regex.h b/benchmarks/benchmarks/espresso/regex.h new file mode 100644 index 0000000..be96614 --- /dev/null +++ b/benchmarks/benchmarks/espresso/regex.h @@ -0,0 +1,269 @@ +#if defined(hpux) +/* Definitions for data structures callers pass the regex library. + Copyright (C) 1985 Free Software Foundation, Inc. + + NO WARRANTY + + BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS" +WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY +AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY +WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR +OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR +DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR +A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS +PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. + + GENERAL PUBLIC LICENSE TO COPY + + 1. You may copy and distribute verbatim copies of this source file +as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy a valid copyright notice "Copyright +(C) 1985 Free Software Foundation, Inc."; and include following the +copyright notice a verbatim copy of the above disclaimer of warranty +and of this License. You may charge a distribution fee for the +physical act of transferring a copy. + + 2. You may modify your copy or copies of this source file or +any portion of it, and copy and distribute such modifications under +the terms of Paragraph 1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating + that you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, + that in whole or in part contains or is a derivative of this + program or any part thereof, to be licensed at no charge to all + third parties on terms identical to those contained in this + License Agreement (except that you may choose to grant more extensive + warranty protection to some or all third parties, at your option). + + c) You may charge a distribution fee for the physical act of + transferring a copy, and you may at your option offer warranty + protection in exchange for a fee. + +Mere aggregation of another unrelated program with this program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other program under the scope of these terms. + + 3. You may copy and distribute this program (or a portion or derivative +of it, under Paragraph 2) in object code or executable form under the terms +of Paragraphs 1 and 2 above provided that you also do one of the following: + + a) accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal + shipping charge) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +For an executable file, complete source code means all the source code for +all modules it contains; but, as a special exception, it need not include +source code for modules which are standard libraries that accompany the +operating system on which the executable file runs. + + 4. You may not copy, sublicense, distribute or transfer this program +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer this program is void and +your rights to use the program under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full compliance. + + 5. If you wish to incorporate parts of this program into other free +programs whose distribution conditions are different, write to the Free +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet +worked out a simple rule that can be stated here, but we will often permit +this. We will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing and reuse of +software. + + +In other words, you are welcome to use, share and improve this program. +You are forbidden to forbid anyone else to use, share and improve +what you give them. Help stamp out software-hoarding! */ + + +/* Define number of parens for which we record the beginnings and ends. + This affects how much space the `struct re_registers' type takes up. */ +#ifndef RE_NREGS +#define RE_NREGS 10 +#endif + +/* These bits are used in the obscure_syntax variable to choose among + alternative regexp syntaxes. */ + +/* 1 means plain parentheses serve as grouping, and backslash + parentheses are needed for literal searching. + 0 means backslash-parentheses are grouping, and plain parentheses + are for literal searching. */ +#define RE_NO_BK_PARENS 1 + +/* 1 means plain | serves as the "or"-operator, and \| is a literal. + 0 means \| serves as the "or"-operator, and | is a literal. */ +#define RE_NO_BK_VBAR 2 + +/* 0 means plain + or ? serves as an operator, and \+, \? are literals. + 1 means \+, \? are operators and plain +, ? are literals. */ +#define RE_BK_PLUS_QM 4 + +/* 1 means | binds tighter than ^ or $. + 0 means the contrary. */ +#define RE_TIGHT_VBAR 8 + +/* 1 means treat \n as an _OR operator + 0 means treat it as a normal character */ +#define RE_NEWLINE_OR 16 + +/* 0 means that a special characters (such as *, ^, and $) always have + their special meaning regardless of the surrounding context. + 1 means that special characters may act as normal characters in some + contexts. Specifically, this applies to: + ^ - only special at the beginning, or after ( or | + $ - only special at the end, or before ) or | + *, +, ? - only special when not after the beginning, (, or | */ +#define RE_CONTEXT_INDEP_OPS 32 + +/* Now define combinations of bits for the standard possibilities. */ +#define RE_SYNTAX_AWK (RE_NO_BK_PARENS | RE_NO_BK_VBAR | RE_CONTEXT_INDEP_OPS) +#define RE_SYNTAX_EGREP (RE_SYNTAX_AWK | RE_NEWLINE_OR) +#define RE_SYNTAX_GREP (RE_BK_PLUS_QM | RE_NEWLINE_OR) +#define RE_SYNTAX_EMACS 0 + +/* This data structure is used to represent a compiled pattern. */ + +struct re_pattern_buffer + { + char *buffer; /* Space holding the compiled pattern commands. */ + int allocated; /* Size of space that buffer points to */ + int used; /* Length of portion of buffer actually occupied */ + char *fastmap; /* Pointer to fastmap, if any, or zero if none. */ + /* re_search uses the fastmap, if there is one, + to skip quickly over totally implausible characters */ + char *translate; /* Translate table to apply to all characters before comparing. + Or zero for no translation. + The translation is applied to a pattern when it is compiled + and to data when it is matched. */ + char fastmap_accurate; + /* Set to zero when a new pattern is stored, + set to one when the fastmap is updated from it. */ + char can_be_null; /* Set to one by compiling fastmap + if this pattern might match the null string. + It does not necessarily match the null string + in that case, but if this is zero, it cannot. + 2 as value means can match null string + but at end of range or before a character + listed in the fastmap. */ + }; + +/* Structure to store "register" contents data in. + + Pass the address of such a structure as an argument to re_match, etc., + if you want this information back. + + start[i] and end[i] record the string matched by \( ... \) grouping i, + for i from 1 to RE_NREGS - 1. + start[0] and end[0] record the entire string matched. */ + +struct re_registers + { + int start[RE_NREGS]; + int end[RE_NREGS]; + }; + +/* These are the command codes that appear in compiled regular expressions, one per byte. + Some command codes are followed by argument bytes. + A command code can specify any interpretation whatever for its arguments. + Zero-bytes may appear in the compiled regular expression. */ + +enum regexpcode + { + unused, + exactn, /* followed by one byte giving n, and then by n literal bytes */ + begline, /* fails unless at beginning of line */ + endline, /* fails unless at end of line */ + jump, /* followed by two bytes giving relative address to jump to */ + on_failure_jump, /* followed by two bytes giving relative address of place + to resume at in case of failure. */ + finalize_jump, /* Throw away latest failure point and then jump to address. */ + maybe_finalize_jump, /* Like jump but finalize if safe to do so. + This is used to jump back to the beginning + of a repeat. If the command that follows + this jump is clearly incompatible with the + one at the beginning of the repeat, such that + we can be sure that there is no use backtracking + out of repetitions already completed, + then we finalize. */ + dummy_failure_jump, /* jump, and push a dummy failure point. + This failure point will be thrown away + if an attempt is made to use it for a failure. + A + construct makes this before the first repeat. */ + anychar, /* matches any one character */ + charset, /* matches any one char belonging to specified set. + First following byte is # bitmap bytes. + Then come bytes for a bit-map saying which chars are in. + Bits in each byte are ordered low-bit-first. + A character is in the set if its bit is 1. + A character too large to have a bit in the map + is automatically not in the set */ + charset_not, /* similar but match any character that is NOT one of those specified */ + start_memory, /* starts remembering the text that is matched + and stores it in a memory register. + followed by one byte containing the register number. + Register numbers must be in the range 0 through NREGS. */ + stop_memory, /* stops remembering the text that is matched + and stores it in a memory register. + followed by one byte containing the register number. + Register numbers must be in the range 0 through NREGS. */ + duplicate, /* match a duplicate of something remembered. + Followed by one byte containing the index of the memory register. */ + before_dot, /* Succeeds if before dot */ + at_dot, /* Succeeds if at dot */ + after_dot, /* Succeeds if after dot */ + begbuf, /* Succeeds if at beginning of buffer */ + endbuf, /* Succeeds if at end of buffer */ + wordchar, /* Matches any word-constituent character */ + notwordchar, /* Matches any char that is not a word-constituent */ + wordbeg, /* Succeeds if at word beginning */ + wordend, /* Succeeds if at word end */ + wordbound, /* Succeeds if at a word boundary */ + notwordbound, /* Succeeds if not at a word boundary */ + syntaxspec, /* Matches any character whose syntax is specified. + followed by a byte which contains a syntax code, Sword or such like */ + notsyntaxspec /* Matches any character whose syntax differs from the specified. */ + }; + +extern char *re_compile_pattern (); +/* Is this really advertised? */ +extern void re_compile_fastmap (); +extern int re_search (), re_search_2 (); +extern int re_match (), re_match_2 (); + +/* 4.2 bsd compatibility (yuck) */ +extern char *re_comp (); +extern int re_exec (); + +#ifdef SYNTAX_TABLE +extern char *re_syntax_table; +#endif +#endif diff --git a/benchmarks/benchmarks/espresso/rows.c b/benchmarks/benchmarks/espresso/rows.c new file mode 100644 index 0000000..6cb38ae --- /dev/null +++ b/benchmarks/benchmarks/espresso/rows.c @@ -0,0 +1,306 @@ +#include "espresso.h" +#include "port.h" +#include "sparse_int.h" + + +/* + * allocate a new row vector + */ +sm_row * +sm_row_alloc() +{ + register sm_row *prow; + +#ifdef FAST_AND_LOOSE + if (sm_row_freelist == NIL(sm_row)) { + prow = ALLOC(sm_row, 1); + } else { + prow = sm_row_freelist; + sm_row_freelist = prow->next_row; + } +#else + prow = ALLOC(sm_row, 1); +#endif + + prow->row_num = 0; + prow->length = 0; + prow->first_col = prow->last_col = NIL(sm_element); + prow->next_row = prow->prev_row = NIL(sm_row); + prow->flag = 0; + prow->user_word = NIL(char); /* for our user ... */ + return prow; +} + + +/* + * free a row vector -- for FAST_AND_LOOSE, this is real cheap for rows; + * however, freeing a column must still walk down the column discarding + * the elements one-by-one; that is the only use for the extra '-DCOLS' + * compile flag ... + */ +void +sm_row_free(prow) +register sm_row *prow; +{ +#if defined(FAST_AND_LOOSE) && ! defined(COLS) + if (prow->first_col != NIL(sm_element)) { + /* Add the linked list of row items to the free list */ + prow->last_col->next_col = sm_element_freelist; + sm_element_freelist = prow->first_col; + } + + /* Add the row to the free list of rows */ + prow->next_row = sm_row_freelist; + sm_row_freelist = prow; +#else + register sm_element *p, *pnext; + + for(p = prow->first_col; p != 0; p = pnext) { + pnext = p->next_col; + sm_element_free(p); + } + FREE(prow); +#endif +} + + +/* + * duplicate an existing row + */ +sm_row * +sm_row_dup(prow) +register sm_row *prow; +{ + register sm_row *pnew; + register sm_element *p; + + pnew = sm_row_alloc(); + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) sm_row_insert(pnew, p->col_num); + } + return pnew; +} + + +/* + * insert an element into a row vector + */ +sm_element * +sm_row_insert(prow, col) +register sm_row *prow; +register int col; +{ + register sm_element *test, *element; + + /* get a new item, save its address */ + sm_element_alloc(element); + test = element; + sorted_insert(sm_element, prow->first_col, prow->last_col, prow->length, + next_col, prev_col, col_num, col, test); + + /* if item was not used, free it */ + if (element != test) { + sm_element_free(element); + } + + /* either way, return the current new value */ + return test; +} + + +/* + * remove an element from a row vector + */ +void +sm_row_remove(prow, col) +register sm_row *prow; +register int col; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0 && p->col_num < col; p = p->next_col) + ; + if (p != 0 && p->col_num == col) { + dll_unlink(p, prow->first_col, prow->last_col, + next_col, prev_col, prow->length); + sm_element_free(p); + } +} + + +/* + * find an element (if it is in the row vector) + */ +sm_element * +sm_row_find(prow, col) +sm_row *prow; +int col; +{ + register sm_element *p; + + for(p = prow->first_col; p != 0 && p->col_num < col; p = p->next_col) + ; + if (p != 0 && p->col_num == col) { + return p; + } else { + return NIL(sm_element); + } +} + +/* + * return 1 if row p2 contains row p1; 0 otherwise + */ +int +sm_row_contains(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_col; + q2 = p2->first_col; + while (q1 != 0) { + if (q2 == 0 || q1->col_num < q2->col_num) { + return 0; + } else if (q1->col_num == q2->col_num) { + q1 = q1->next_col; + q2 = q2->next_col; + } else { + q2 = q2->next_col; + } + } + return 1; +} + + +/* + * return 1 if row p1 and row p2 share an element in common + */ +int +sm_row_intersects(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_col; + q2 = p2->first_col; + if (q1 == 0 || q2 == 0) return 0; + for(;;) { + if (q1->col_num < q2->col_num) { + if ((q1 = q1->next_col) == 0) { + return 0; + } + } else if (q1->col_num > q2->col_num) { + if ((q2 = q2->next_col) == 0) { + return 0; + } + } else { + return 1; + } + } +} + + +/* + * compare two rows, lexical ordering + */ +int +sm_row_compare(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + + q1 = p1->first_col; + q2 = p2->first_col; + while(q1 != 0 && q2 != 0) { + if (q1->col_num != q2->col_num) { + return q1->col_num - q2->col_num; + } + q1 = q1->next_col; + q2 = q2->next_col; + } + + if (q1 != 0) { + return 1; + } else if (q2 != 0) { + return -1; + } else { + return 0; + } +} + + +/* + * return the intersection + */ +sm_row * +sm_row_and(p1, p2) +sm_row *p1, *p2; +{ + register sm_element *q1, *q2; + register sm_row *result; + + result = sm_row_alloc(); + q1 = p1->first_col; + q2 = p2->first_col; + if (q1 == 0 || q2 == 0) return result; + for(;;) { + if (q1->col_num < q2->col_num) { + if ((q1 = q1->next_col) == 0) { + return result; + } + } else if (q1->col_num > q2->col_num) { + if ((q2 = q2->next_col) == 0) { + return result; + } + } else { + (void) sm_row_insert(result, q1->col_num); + if ((q1 = q1->next_col) == 0) { + return result; + } + if ((q2 = q2->next_col) == 0) { + return result; + } + } + } +} + +int +sm_row_hash(prow, modulus) +sm_row *prow; +int modulus; +{ + register int sum; + register sm_element *p; + + sum = 0; + for(p = prow->first_col; p != 0; p = p->next_col) { + sum = (sum*17 + p->col_num) % modulus; + } + return sum; +} + +/* + * remove an element from a row vector (given a pointer to the element) + */ +void +sm_row_remove_element(prow, p) +register sm_row *prow; +register sm_element *p; +{ + dll_unlink(p, prow->first_col, prow->last_col, + next_col, prev_col, prow->length); + sm_element_free(p); +} + + +void +sm_row_print(fp, prow) +FILE *fp; +sm_row *prow; +{ + sm_element *p; + + for(p = prow->first_col; p != 0; p = p->next_col) { + (void) fprintf(fp, " %d", p->col_num); + } +} diff --git a/benchmarks/benchmarks/espresso/set.c b/benchmarks/benchmarks/espresso/set.c new file mode 100644 index 0000000..4c6ad15 --- /dev/null +++ b/benchmarks/benchmarks/espresso/set.c @@ -0,0 +1,811 @@ +/* + * set.c -- routines for maniuplating sets and set families + */ + +/* LINTLIBRARY */ + +#include "espresso.h" +static pset_family set_family_garbage = NULL; + +static int intcpy(d, s, n) +register unsigned int *d, *s; +register long n; +{ + register int i; + for(i = 0; i < n; i++) { + *d++ = *s++; + } +} + + +/* bit_index -- find first bit (from LSB) in a word (MSB=bit n, LSB=bit 0) */ +int bit_index(a) +register unsigned int a; +{ + register int i; + if (a == 0) + return -1; + for(i = 0; (a & 1) == 0; a >>= 1, i++) + ; + return i; +} + + +/* set_ord -- count number of elements in a set */ +int set_ord(a) +register pset a; +{ + register int i, sum = 0; + register unsigned int val; + for(i = LOOP(a); i > 0; i--) + if ((val = a[i]) != 0) + sum += count_ones(val); + return sum; +} + +/* set_dist -- distance between two sets (# elements in common) */ +int set_dist(a, b) +register pset a, b; +{ + register int i, sum = 0; + register unsigned int val; + for(i = LOOP(a); i > 0; i--) + if ((val = a[i] & b[i]) != 0) + sum += count_ones(val); + return sum; +} + +/* set_clear -- make "r" the empty set of "size" elements */ +pset set_clear(r, size) +register pset r; +int size; +{ + register int i = LOOPINIT(size); + *r = i; do r[i] = 0; while (--i > 0); + return r; +} + +/* set_fill -- make "r" the universal set of "size" elements */ +pset set_fill(r, size) +register pset r; +register int size; +{ + register int i = LOOPINIT(size); + *r = i; + r[i] = ~ (unsigned) 0; + r[i] >>= i * BPI - size; + while (--i > 0) + r[i] = ~ (unsigned) 0; + return r; +} + +/* set_copy -- copy set a into set r */ +pset set_copy(r, a) +register pset r, a; +{ + register int i = LOOPCOPY(a); + do r[i] = a[i]; while (--i >= 0); + return r; +} + +/* set_and -- compute intersection of sets "a" and "b" */ +pset set_and(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = a[i] & b[i]; while (--i > 0); + return r; +} + +/* set_or -- compute union of sets "a" and "b" */ +pset set_or(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = a[i] | b[i]; while (--i > 0); + return r; +} + +/* set_diff -- compute difference of sets "a" and "b" */ +pset set_diff(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = a[i] & ~b[i]; while (--i > 0); + return r; +} + +/* set_xor -- compute exclusive-or of sets "a" and "b" */ +pset set_xor(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); +#ifdef IBM_WATC + PUTLOOP(r,i); do r[i] = (a[i]&~b[i]) | (~a[i]&b[i]); while (--i > 0); +#else + PUTLOOP(r,i); do r[i] = a[i] ^ b[i]; while (--i > 0); +#endif + return r; +} + +/* set_merge -- compute "a" & "mask" | "b" & ~ "mask" */ +pset set_merge(r, a, b, mask) +register pset r, a, b, mask; +{ + register int i = LOOP(a); + PUTLOOP(r,i); do r[i] = (a[i]&mask[i]) | (b[i]&~mask[i]); while (--i > 0); + return r; +} + +/* set_andp -- compute intersection of sets "a" and "b" , TRUE if nonempty */ +bool set_andp(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + register unsigned int x = 0; + PUTLOOP(r,i); do {r[i] = a[i] & b[i]; x |= r[i];} while (--i > 0); + return x != 0; +} + +/* set_orp -- compute union of sets "a" and "b" , TRUE if nonempty */ +bool set_orp(r, a, b) +register pset r, a, b; +{ + register int i = LOOP(a); + register unsigned int x = 0; + PUTLOOP(r,i); do {r[i] = a[i] | b[i]; x |= r[i];} while (--i > 0); + return x != 0; +} + +/* setp_empty -- check if the set "a" is empty */ +bool setp_empty(a) +register pset a; +{ + register int i = LOOP(a); + do if (a[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* setp_full -- check if the set "a" is the full set of "size" elements */ +bool setp_full(a, size) +register pset a; +register int size; +{ + register int i = LOOP(a); + register unsigned int test; + test = ~ (unsigned) 0; + test >>= i * BPI - size; + if (a[i] != test) + return FALSE; + while (--i > 0) + if (a[i] != (~(unsigned) 0)) + return FALSE; + return TRUE; +} + +/* setp_equal -- check if the set "a" equals set "b" */ +bool setp_equal(a, b) +register pset a, b; +{ + register int i = LOOP(a); + do if (a[i] != b[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* setp_disjoint -- check if intersection of "a" and "b" is empty */ +bool setp_disjoint(a, b) +register pset a, b; +{ + register int i = LOOP(a); + do if (a[i] & b[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* setp_implies -- check if "a" implies "b" ("b" contains "a") */ +bool setp_implies(a, b) +register pset a, b; +{ + register int i = LOOP(a); + do if (a[i] & ~b[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* sf_or -- form the "or" of all sets in a set family */ +pset sf_or(A) +pset_family A; +{ + register pset or, last, p; + + or = set_new(A->sf_size); + foreach_set(A, last, p) + INLINEset_or(or, or, p); + return or; +} + +/* sf_and -- form the "and" of all sets in a set family */ +pset sf_and(A) +pset_family A; +{ + register pset and, last, p; + + and = set_fill(set_new(A->sf_size), A->sf_size); + foreach_set(A, last, p) + INLINEset_and(and, and, p); + return and; +} + +/* sf_active -- make all members of the set family active */ +pset_family sf_active(A) +pset_family A; +{ + register pset p, last; + foreach_set(A, last, p) { + SET(p, ACTIVE); + } + A->active_count = A->count; + return A; +} + + +/* sf_inactive -- remove all inactive cubes in a set family */ +pset_family sf_inactive(A) +pset_family A; +{ + register pset p, last, pdest; + + pdest = A->data; + foreach_set(A, last, p) { + if (TESTP(p, ACTIVE)) { + if (pdest != p) { + INLINEset_copy(pdest, p); + } + pdest += A->wsize; + } else { + A->count--; + } + } + return A; +} + + +/* sf_copy -- copy a set family */ +pset_family sf_copy(R, A) +pset_family R, A; +{ + R->sf_size = A->sf_size; + R->wsize = A->wsize; +/*R->capacity = A->count;*/ +/*R->data = REALLOC(unsigned int, R->data, (long) R->capacity * R->wsize);*/ + R->count = A->count; + R->active_count = A->active_count; + intcpy(R->data, A->data, (long) A->wsize * A->count); + return R; +} + + +/* sf_join -- join A and B into a single set_family */ +pset_family sf_join(A, B) +pset_family A, B; +{ + pset_family R; + long asize = A->count * A->wsize; + long bsize = B->count * B->wsize; + + if (A->sf_size != B->sf_size) fatal("sf_join: sf_size mismatch"); + R = sf_new(A->count + B->count, A->sf_size); + R->count = A->count + B->count; + R->active_count = A->active_count + B->active_count; + intcpy(R->data, A->data, asize); + intcpy(R->data + asize, B->data, bsize); + return R; +} + + +/* sf_append -- append the sets of B to the end of A, and dispose of B */ +pset_family sf_append(A, B) +pset_family A, B; +{ + long asize = A->count * A->wsize; + long bsize = B->count * B->wsize; + + if (A->sf_size != B->sf_size) fatal("sf_append: sf_size mismatch"); + A->capacity = A->count + B->count; + A->data = REALLOC(unsigned int, A->data, (long) A->capacity * A->wsize); + intcpy(A->data + asize, B->data, bsize); + A->count += B->count; + A->active_count += B->active_count; + sf_free(B); + return A; +} + + +/* sf_new -- allocate "num" sets of "size" elements each */ +pset_family sf_new(num, size) +int num, size; +{ + pset_family A; + if (set_family_garbage == NULL) { + A = ALLOC(set_family_t, 1); + } else { + A = set_family_garbage; + set_family_garbage = A->next; + } + A->sf_size = size; + A->wsize = SET_SIZE(size); + A->capacity = num; + A->data = ALLOC(unsigned int, (long) A->capacity * A->wsize); + A->count = 0; + A->active_count = 0; + return A; +} + + +/* sf_save -- create a duplicate copy of a set family */ +pset_family sf_save(A) +register pset_family A; +{ + return sf_copy(sf_new(A->count, A->sf_size), A); +} + + +/* sf_free -- free the storage allocated for a set family */ +void sf_free(A) +pset_family A; +{ + FREE(A->data); + A->next = set_family_garbage; + set_family_garbage = A; +} + + +/* sf_cleanup -- free all of the set families from the garbage list */ +void sf_cleanup() +{ + register pset_family p, pnext; + for(p = set_family_garbage; p != (pset_family) NULL; p = pnext) { + pnext = p->next; + FREE(p); + } + set_family_garbage = (pset_family) NULL; +} + + +/* sf_addset -- add a set to the end of a set family */ +pset_family sf_addset(A, s) +pset_family A; +pset s; +{ + register pset p; + + if (A->count >= A->capacity) { + A->capacity = A->capacity + A->capacity/2 + 1; + A->data = REALLOC(unsigned int, A->data, (long) A->capacity * A->wsize); + } + p = GETSET(A, A->count++); + INLINEset_copy(p, s); + return A; +} + +/* sf_delset -- delete a set from a set family */ +void sf_delset(A, i) +pset_family A; +int i; +{ (void) set_copy(GETSET(A,i), GETSET(A, --A->count));} + +/* sf_print -- print a set_family as a set (list the element numbers) */ +void sf_print(A) +pset_family A; +{ + char *ps1(); + register pset p; + register int i; + foreachi_set(A, i, p) + printf("A[%d] = %s\n", i, ps1(p)); +} + +/* sf_bm_print -- print a set_family as a bit-matrix */ +void sf_bm_print(A) +pset_family A; +{ + char *pbv1(); + register pset p; + register int i; + foreachi_set(A, i, p) + printf("[%4d] %s\n", i, pbv1(p, A->sf_size)); +} + + +/* sf_write -- output a set family in an unintelligable manner */ +void sf_write(fp, A) +FILE *fp; +pset_family A; +{ + register pset p, last; + fprintf(fp, "%d %d\n", A->count, A->sf_size); + foreach_set(A, last, p) + set_write(fp, p); + (void) fflush(fp); +} + + +/* sf_read -- read a set family written by sf_write */ +pset_family sf_read(fp) +FILE *fp; +{ + int i, j; + register pset p, last; + pset_family A; + + (void) fscanf(fp, "%d %d\n", &i, &j); + A = sf_new(i, j); + A->count = i; + foreach_set(A, last, p) { + (void) fscanf(fp, "%x", p); + for(j = 1; j <= LOOP(p); j++) + (void) fscanf(fp, "%x", p+j); + } + return A; +} + + +/* set_write -- output a set in an unintelligable manner */ +void set_write(fp, a) +register FILE *fp; +register pset a; +{ + register int n = LOOP(a), j; + + for(j = 0; j <= n; j++) { + fprintf(fp, "%x ", a[j]); + if ((j+1) % 8 == 0 && j != n) + fprintf(fp, "\n\t"); + } + fprintf(fp, "\n"); +} + + +/* sf_bm_read -- read a set family written by sf_bm_print (almost) */ +pset_family sf_bm_read(fp) +FILE *fp; +{ + int i, j, rows, cols; + register pset pdest; + pset_family A; + + (void) fscanf(fp, "%d %d\n", &rows, &cols); + A = sf_new(rows, cols); + for(i = 0; i < rows; i++) { + pdest = GETSET(A, A->count++); + (void) set_clear(pdest, A->sf_size); + for(j = 0; j < cols; j++) { + switch(getc(fp)) { + case '0': + break; + case '1': + set_insert(pdest, j); + break; + default: + fatal("Error reading set family"); + } + } + if (getc(fp) != '\n') { + fatal("Error reading set family (at end of line)"); + } + } + return A; +} + + + +/* ps1 -- convert a set into a printable string */ +#define largest_string 120 +static char s1[largest_string]; +char *ps1(a) +register pset a; +{ + register int i, num, l, len = 0, n = NELEM(a); + char temp[20]; + bool first = TRUE; + + s1[len++] = '['; + for(i = 0; i < n; i++) + if (is_in_set(a,i)) { + if (! first) + s1[len++] = ','; + first = FALSE; num = i; + /* Generate digits (reverse order) */ + l = 0; do temp[l++] = num % 10 + '0'; while ((num /= 10) > 0); + /* Copy them back in correct order */ + do s1[len++] = temp[--l]; while (l > 0); + if (len > largest_string-15) { + s1[len++] = '.'; s1[len++] = '.'; s1[len++] = '.'; + break; + } + } + + s1[len++] = ']'; + s1[len++] = '\0'; + return s1; +} + +/* pbv1 -- print bit-vector */ +char *pbv1(s, n) +pset s; +int n; +{ + register int i; + for(i = 0; i < n; i++) + s1[i] = is_in_set(s,i) ? '1' : '0'; + s1[n] = '\0'; + return s1; +} + + +/* set_adjcnt -- adjust the counts for a set by "weight" */ +void +set_adjcnt(a, count, weight) +register pset a; +register int *count, weight; +{ + register int i, base; + register unsigned int val; + + for(i = LOOP(a); i > 0; ) { + for(val = a[i], base = --i << LOGBPI; val != 0; base++, val >>= 1) { + if (val & 1) { + count[base] += weight; + } + } + } +} + + + +/* sf_count -- perform a column sum over a set family */ +int *sf_count(A) +pset_family A; +{ + register pset p, last; + register int i, base, *count; + register unsigned int val; + + count = ALLOC(int, A->sf_size); + for(i = A->sf_size - 1; i >= 0; i--) { + count[i] = 0; + } + + foreach_set(A, last, p) { + for(i = LOOP(p); i > 0; ) { + for(val = p[i], base = --i << LOGBPI; val != 0; base++, val >>= 1) { + if (val & 1) { + count[base]++; + } + } + } + } + return count; +} + + +/* sf_count_restricted -- perform a column sum over a set family, restricting + * to only the columns which are in r; also, the columns are weighted by the + * number of elements which are in each row + */ +int *sf_count_restricted(A, r) +pset_family A; +register pset r; +{ + register pset p; + register int i, base, *count; + register unsigned int val; + int weight; + pset last; + + count = ALLOC(int, A->sf_size); + for(i = A->sf_size - 1; i >= 0; i--) { + count[i] = 0; + } + + /* Loop for each set */ + foreach_set(A, last, p) { + weight = 1024 / (set_ord(p) - 1); + for(i = LOOP(p); i > 0; ) { + for(val=p[i]&r[i], base= --i<>= 1) { + if (val & 1) { + count[base] += weight; + } + } + } + } + return count; +} + + +/* + * sf_delc -- delete columns first ... last of A + */ +pset_family sf_delc(A, first, last) +pset_family A; +int first, last; +{ + return sf_delcol(A, first, last-first + 1); +} + + +/* + * sf_addcol -- add columns to a set family; includes a quick check to see + * if there is already enough room (and hence, can avoid copying) + */ +pset_family sf_addcol(A, firstcol, n) +pset_family A; +int firstcol, n; +{ + int maxsize; + + /* Check if adding columns at the end ... */ + if (firstcol == A->sf_size) { + /* If so, check if there is already enough room */ + maxsize = BPI * LOOPINIT(A->sf_size); + if ((A->sf_size + n) <= maxsize) { + A->sf_size += n; + return A; + } + } + return sf_delcol(A, firstcol, -n); +} + +/* + * sf_delcol -- add/delete columns to/from a set family + * + * if n > 0 then n columns starting from firstcol are deleted if n < 0 + * then n blank columns are inserted starting at firstcol + * (i.e., the first new column number is firstcol) + * + * This is done by copying columns in the array which is a relatively + * slow operation. + */ +pset_family sf_delcol(A, firstcol, n) +pset_family A; +register int firstcol, n; +{ + register pset p, last, pdest; + register int i; + pset_family B; + + B = sf_new(A->count, A->sf_size - n); + foreach_set(A, last, p) { + pdest = GETSET(B, B->count++); + INLINEset_clear(pdest, B->sf_size); + for(i = 0; i < firstcol; i++) + if (is_in_set(p, i)) + set_insert(pdest, i); + for(i = n > 0 ? firstcol + n : firstcol; i < A->sf_size; i++) + if (is_in_set(p, i)) + set_insert(pdest, i - n); + } + sf_free(A); + return B; +} + + +/* + * sf_copy_col -- copy column "srccol" from "src" to column "dstcol" of "dst" + */ +pset_family sf_copy_col(dst, dstcol, src, srccol) +pset_family dst, src; +int dstcol, srccol; +{ + register pset last, p, pdest; + register int word_test, word_set; + unsigned int bit_set, bit_test; + + /* CHEAT! form these constants outside the loop */ + word_test = WHICH_WORD(srccol); + bit_test = 1 << WHICH_BIT(srccol); + word_set = WHICH_WORD(dstcol); + bit_set = 1 << WHICH_BIT(dstcol); + + pdest = dst->data; + foreach_set(src, last, p) { + if ((p[word_test] & bit_test) != 0) + pdest[word_set] |= bit_set; +/* + * equivalent code for this is ... + * if (is_in_set(p, srccol)) set_insert(pdest, destcol); + */ + pdest += dst->wsize; + } + return dst; +} + + + +/* + * sf_compress -- delete columns from a matrix + */ +pset_family sf_compress(A, c) +pset_family A; /* will be freed */ +register pset c; +{ + register pset p; + register int i, bcol; + pset_family B; + + /* create a clean set family for the result */ + B = sf_new(A->count, set_ord(c)); + for(i = 0; i < A->count; i++) { + p = GETSET(B, B->count++); + INLINEset_clear(p, B->sf_size); + } + + /* copy each column of A which has a 1 in c */ + bcol = 0; + for(i = 0; i < A->sf_size; i++) { + if (is_in_set(c, i)) { + (void) sf_copy_col(B, bcol++, A, i); + } + } + sf_free(A); + return B; +} + + + +/* + * sf_transpose -- transpose a bit matrix + * + * There are trickier ways of doing this, but this works. + */ +pset_family sf_transpose(A) +pset_family A; +{ + pset_family B; + register pset p; + register int i, j; + + B = sf_new(A->sf_size, A->count); + B->count = A->sf_size; + foreachi_set(B, i, p) { + INLINEset_clear(p, B->sf_size); + } + foreachi_set(A, i, p) { + for(j = 0; j < A->sf_size; j++) { + if (is_in_set(p, j)) { + set_insert(GETSET(B, j), i); + } + } + } + sf_free(A); + return B; +} + + +/* + * sf_permute -- permute the columns of a set_family + * + * permute is an array of integers containing column numbers of A which + * are to be retained. + */ +pset_family sf_permute(A, permute, npermute) +pset_family A; +register int *permute, npermute; +{ + pset_family B; + register pset p, last, pdest; + register int j; + + B = sf_new(A->count, npermute); + B->count = A->count; + foreach_set(B, last, p) + INLINEset_clear(p, npermute); + + pdest = B->data; + foreach_set(A, last, p) { + for(j = 0; j < npermute; j++) + if (is_in_set(p, permute[j])) + set_insert(pdest, j); + pdest += B->wsize; + } + sf_free(A); + return B; +} diff --git a/benchmarks/benchmarks/espresso/setc.c b/benchmarks/benchmarks/espresso/setc.c new file mode 100644 index 0000000..a2d06c9 --- /dev/null +++ b/benchmarks/benchmarks/espresso/setc.c @@ -0,0 +1,474 @@ +/* + setc.c -- massive bit-hacking for performing special "cube"-type + operations on a set + + The basic trick used for binary valued variables is the following: + + If a[w] and b[w] contain a full word of binary variables, then: + + 1) to get the full word of their intersection, we use + + x = a[w] & b[w]; + + + 2) to see if the intersection is null in any variables, we examine + + x = ~(x | x >> 1) & DISJOINT; + + this will have a single 1 in each binary variable for which + the intersection is null. In particular, if this is zero, + then there are no disjoint variables; or, if this is nonzero, + then there is at least one disjoint variable. A "count_ones" + over x will tell in how many variables they have an null + intersection. + + + 3) to get a mask which selects the disjoint variables, we use + + (x | x << 1) + + this provides a selector which can be used to see where + they have an null intersection + + + cdist return distance between two cubes + cdist0 return true if two cubes are distance 0 apart + cdist01 return distance, or 2 if distance exceeds 1 + consensus compute consensus of two cubes distance 1 apart + force_lower expand hack (for now), related to consensus +*/ + +#include "espresso.h" + +/* see if the cube has a full row of 1's (with respect to cof) */ +bool full_row(p, cof) +IN register pcube p, cof; +{ + register int i = LOOP(p); + do if ((p[i] | cof[i]) != cube.fullset[i]) return FALSE; while (--i > 0); + return TRUE; +} + +/* + cdist0 -- return TRUE if a and b are distance 0 apart +*/ + +bool cdist0(a, b) +register pcube a, b; +{ + { /* Check binary variables */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (~(x | x >> 1) & cube.inmask) + return FALSE; /* disjoint in some variable */ + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (~(x | x >> 1) & DISJOINT) + return FALSE; /* disjoint in some variable */ + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + return FALSE; /* disjoint in this variable */ + nextvar: ; + } + } + return TRUE; +} + +/* + cdist01 -- return the "distance" between two cubes (defined as the + number of null variables in their intersection). If the distance + exceeds 1, the value 2 is returned. +*/ + +int cdist01(a, b) +register pset a, b; +{ + int dist = 0; + + { /* Check binary variables */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (x = ~ (x | x >> 1) & cube.inmask) + if ((dist = count_ones(x)) > 1) + return 2; + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (x = ~ (x | x >> 1) & DISJOINT) + if (dist == 1 || (dist += count_ones(x)) > 1) + return 2; + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + if (++dist > 1) + return 2; + nextvar: ; + } + } + return dist; +} + +/* + cdist -- return the "distance" between two cubes (defined as the + number of null variables in their intersection). +*/ + +int cdist(a, b) +register pset a, b; +{ + int dist = 0; + + { /* Check binary variables */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (x = ~ (x | x >> 1) & cube.inmask) + dist = count_ones(x); + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (x = ~ (x | x >> 1) & DISJOINT) + dist += count_ones(x); + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + dist++; + nextvar: ; + } + } + return dist; +} + +/* + force_lower -- Determine which variables of a do not intersect b. +*/ + +pset force_lower(xlower, a, b) +INOUT pset xlower; +IN register pset a, b; +{ + + { /* Check binary variables (if any) */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] & b[last]; + if (x = ~(x | x >> 1) & cube.inmask) + xlower[last] |= (x | (x << 1)) & a[last]; + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] & b[w]; + if (x = ~(x | x >> 1) & DISJOINT) + xlower[w] |= (x | (x << 1)) & a[w]; + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (a[w] & b[w] & mask[w]) + goto nextvar; + for(w = cube.first_word[var]; w <= last; w++) + xlower[w] |= a[w] & mask[w]; + nextvar: ; + } + } + return xlower; +} + +/* + consensus -- multiple-valued consensus + + Although this looks very messy, the idea is to compute for r the + "and" of the cubes a and b for each variable, unless the "and" is + null in a variable, in which case the "or" of a and b is computed + for this variable. + + Because we don't check how many variables are null in the + intersection of a and b, the returned value for r really only + represents the consensus when a and b are distance 1 apart. +*/ + +void consensus(r, a, b) +INOUT pcube r; +IN register pcube a, b; +{ + INLINEset_clear(r, cube.size); + + { /* Check binary variables (if any) */ + register int w, last; register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + r[last] = x = a[last] & b[last]; + if (x = ~(x | x >> 1) & cube.inmask) + r[last] |= (x | (x << 1)) & (a[last] | b[last]); + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + r[w] = x = a[w] & b[w]; + if (x = ~(x | x >> 1) & DISJOINT) + r[w] |= (x | (x << 1)) & (a[w] | b[w]); + } + } + } + + + { /* Check the multiple-valued variables */ + bool empty; int var; unsigned int x; + register int w, last; register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; + last = cube.last_word[var]; + empty = TRUE; + for(w = cube.first_word[var]; w <= last; w++) + if (x = a[w] & b[w] & mask[w]) + empty = FALSE, r[w] |= x; + if (empty) + for(w = cube.first_word[var]; w <= last; w++) + r[w] |= mask[w] & (a[w] | b[w]); + } + } +} + +/* + cactive -- return the index of the single active variable in + the cube, or return -1 if there are none or more than 2. +*/ + +int cactive(a) +register pcube a; +{ + int active = -1, dist = 0, bit_index(); + + { /* Check binary variables */ + register int w, last; + register unsigned int x; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last]; + if (x = ~ (x & x >> 1) & cube.inmask) { + if ((dist = count_ones(x)) > 1) + return -1; /* more than 2 active variables */ + active = (last-1)*(BPI/2) + bit_index(x) / 2; + } + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w]; + if (x = ~ (x & x >> 1) & DISJOINT) { + if ((dist += count_ones(x)) > 1) + return -1; /* more than 2 active variables */ + active = (w-1)*(BPI/2) + bit_index(x) / 2; + } + } + } + } + + { /* Check the multiple-valued variables */ + register int w, var, last; + register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; + last = cube.last_word[var]; + for(w = cube.first_word[var]; w <= last; w++) + if (mask[w] & ~ a[w]) { + if (++dist > 1) + return -1; + active = var; + break; + } + } + } + return active; +} + +/* + ccommon -- return TRUE if a and b are share "active" variables + active variables include variables that are empty; +*/ + +bool ccommon(a, b, cof) +register pcube a, b, cof; +{ + { /* Check binary variables */ + int last; + register int w; + register unsigned int x, y; + if ((last = cube.inword) != -1) { + + /* Check the partial word of binary variables */ + x = a[last] | cof[last]; + y = b[last] | cof[last]; + if (~(x & x>>1) & ~(y & y>>1) & cube.inmask) + return TRUE; + + /* Check the full words of binary variables */ + for(w = 1; w < last; w++) { + x = a[w] | cof[w]; + y = b[w] | cof[w]; + if (~(x & x>>1) & ~(y & y>>1) & DISJOINT) + return TRUE; + } + } + } + + { /* Check the multiple-valued variables */ + int var; + register int w, last; + register pcube mask; + for(var = cube.num_binary_vars; var < cube.num_vars; var++) { + mask = cube.var_mask[var]; last = cube.last_word[var]; + /* Check for some part missing from a */ + for(w = cube.first_word[var]; w <= last; w++) + if (mask[w] & ~a[w] & ~cof[w]) { + + /* If so, check for some part missing from b */ + for(w = cube.first_word[var]; w <= last; w++) + if (mask[w] & ~b[w] & ~cof[w]) + return TRUE; /* both active */ + break; + } + } + } + return FALSE; +} + +/* + These routines compare two sets (cubes) for the qsort() routine and + return: + + -1 if set a is to precede set b + 0 if set a and set b are equal + 1 if set a is to follow set b + + Usually the SIZE field of the set is assumed to contain the size + of the set (which will save recomputing the set size during the + sort). For distance-1 merging, the global variable cube.temp[0] is + a mask which mask's-out the merging variable. +*/ + +/* descend -- comparison for descending sort on set size */ +int descend(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b; + if (SIZE(a1) > SIZE(b1)) return -1; + else if (SIZE(a1) < SIZE(b1)) return 1; + else { + register int i = LOOP(a1); + do + if (a1[i] > b1[i]) return -1; else if (a1[i] < b1[i]) return 1; + while (--i > 0); + } + return 0; +} + +/* ascend -- comparison for ascending sort on set size */ +int ascend(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b; + if (SIZE(a1) > SIZE(b1)) return 1; + else if (SIZE(a1) < SIZE(b1)) return -1; + else { + register int i = LOOP(a1); + do + if (a1[i] > b1[i]) return 1; else if (a1[i] < b1[i]) return -1; + while (--i > 0); + } + return 0; +} + + +/* lex_order -- comparison for "lexical" ordering of cubes */ +int lex_order(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b; + register int i = LOOP(a1); + do + if (a1[i] > b1[i]) return -1; else if (a1[i] < b1[i]) return 1; + while (--i > 0); + return 0; +} + + +/* d1_order -- comparison for distance-1 merge routine */ +int d1_order(a, b) +pset *a, *b; +{ + register pset a1 = *a, b1 = *b, c1 = cube.temp[0]; + register int i = LOOP(a1); + register unsigned int x1, x2; + do + if ((x1 = a1[i] | c1[i]) > (x2 = b1[i] | c1[i])) return -1; + else if (x1 < x2) return 1; + while (--i > 0); + return 0; +} + + +/* desc1 -- comparison (without indirection) for descending sort */ +/* also has effect of handling NULL pointers,and a NULL pointer has smallest +order */ +int desc1(a, b) +register pset a, b; +{ + if (a == (pset) NULL) + return (b == (pset) NULL) ? 0 : 1; + else if (b == (pset) NULL) + return -1; + if (SIZE(a) > SIZE(b)) return -1; + else if (SIZE(a) < SIZE(b)) return 1; + else { + register int i = LOOP(a); + do + if (a[i] > b[i]) return -1; else if (a[i] < b[i]) return 1; + while (--i > 0); + } + return 0; +} diff --git a/benchmarks/benchmarks/espresso/sharp.c b/benchmarks/benchmarks/espresso/sharp.c new file mode 100644 index 0000000..24401df --- /dev/null +++ b/benchmarks/benchmarks/espresso/sharp.c @@ -0,0 +1,238 @@ +/* + sharp.c -- perform sharp, disjoint sharp, and intersection +*/ + +#include "espresso.h" + +long start_time; + + +/* cv_sharp -- form the sharp product between two covers */ +pcover cv_sharp(A, B) +pcover A, B; +{ + pcube last, p; + pcover T; + + T = new_cover(0); + foreach_set(A, last, p) + T = sf_union(T, cb_sharp(p, B)); + return T; +} + + +/* cb_sharp -- form the sharp product between a cube and a cover */ +pcover cb_sharp(c, T) +pcube c; +pcover T; +{ + if (T->count == 0) { + T = sf_addset(new_cover(1), c); + } else { + start_time = ptime(); + T = cb_recur_sharp(c, T, 0, T->count-1, 0); + } + return T; +} + + +/* recursive formulation to provide balanced merging */ +pcover cb_recur_sharp(c, T, first, last, level) +pcube c; +pcover T; +int first, last, level; +{ + pcover temp, left, right; + int middle; + + if (first == last) { + temp = sharp(c, GETSET(T, first)); + } else { + middle = (first + last) / 2; + left = cb_recur_sharp(c, T, first, middle, level+1); + right = cb_recur_sharp(c, T, middle+1, last, level+1); + temp = cv_intersect(left, right); + if ((debug & SHARP) && level < 4) { + printf("# SHARP[%d]: %4d = %4d x %4d, time = %s\n", + level, temp->count, left->count, right->count, + print_time(ptime() - start_time)); + (void) fflush(stdout); + } + free_cover(left); + free_cover(right); + } + return temp; +} + + +/* sharp -- form the sharp product between two cubes */ +pcover sharp(a, b) +pcube a, b; +{ + register int var; + register pcube d=cube.temp[0], temp=cube.temp[1], temp1=cube.temp[2]; + pcover r = new_cover(cube.num_vars); + + if (cdist0(a, b)) { + set_diff(d, a, b); + for(var = 0; var < cube.num_vars; var++) { + if (! setp_empty(set_and(temp, d, cube.var_mask[var]))) { + set_diff(temp1, a, cube.var_mask[var]); + set_or(GETSET(r, r->count++), temp, temp1); + } + } + } else { + r = sf_addset(r, a); + } + return r; +} + +pcover make_disjoint(A) +pcover A; +{ + pcover R, new; + register pset last, p; + + R = new_cover(0); + foreach_set(A, last, p) { + new = cb_dsharp(p, R); + R = sf_append(R, new); + } + return R; +} + + +/* cv_dsharp -- disjoint-sharp product between two covers */ +pcover cv_dsharp(A, B) +pcover A, B; +{ + register pcube last, p; + pcover T; + + T = new_cover(0); + foreach_set(A, last, p) { + T = sf_union(T, cb_dsharp(p, B)); + } + return T; +} + + +/* cb1_dsharp -- disjoint-sharp product between a cover and a cube */ +pcover cb1_dsharp(T, c) +pcover T; +pcube c; +{ + pcube last, p; + pcover R; + + R = new_cover(T->count); + foreach_set(T, last, p) { + R = sf_union(R, dsharp(p, c)); + } + return R; +} + + +/* cb_dsharp -- disjoint-sharp product between a cube and a cover */ +pcover cb_dsharp(c, T) +pcube c; +pcover T; +{ + pcube last, p; + pcover Y, Y1; + + if (T->count == 0) { + Y = sf_addset(new_cover(1), c); + } else { + Y = new_cover(T->count); + set_copy(GETSET(Y,Y->count++), c); + foreach_set(T, last, p) { + Y1 = cb1_dsharp(Y, p); + free_cover(Y); + Y = Y1; + } + } + return Y; +} + + +/* dsharp -- form the disjoint-sharp product between two cubes */ +pcover dsharp(a, b) +pcube a, b; +{ + register pcube mask, diff, and, temp, temp1 = cube.temp[0]; + int var; + pcover r; + + r = new_cover(cube.num_vars); + + if (cdist0(a, b)) { + diff = set_diff(new_cube(), a, b); + and = set_and(new_cube(), a, b); + mask = new_cube(); + for(var = 0; var < cube.num_vars; var++) { + /* check if position var of "a and not b" is not empty */ + if (! setp_disjoint(diff, cube.var_mask[var])) { + + /* coordinate var equals the difference between a and b */ + temp = GETSET(r, r->count++); + (void) set_and(temp, diff, cube.var_mask[var]); + + /* coordinates 0 ... var-1 equal the intersection */ + INLINEset_and(temp1, and, mask); + INLINEset_or(temp, temp, temp1); + + /* coordinates var+1 .. cube.num_vars equal a */ + set_or(mask, mask, cube.var_mask[var]); + INLINEset_diff(temp1, a, mask); + INLINEset_or(temp, temp, temp1); + } + } + free_cube(diff); + free_cube(and); + free_cube(mask); + } else { + r = sf_addset(r, a); + } + return r; +} + +/* cv_intersect -- form the intersection of two covers */ + +#define MAGIC 500 /* save 500 cubes before containment */ + +pcover cv_intersect(A, B) +pcover A, B; +{ + register pcube pi, pj, lasti, lastj, pt; + pcover T, Tsave = NULL; + + /* How large should each temporary result cover be ? */ + T = new_cover(MAGIC); + pt = T->data; + + /* Form pairwise intersection of each cube of A with each cube of B */ + foreach_set(A, lasti, pi) { + foreach_set(B, lastj, pj) { + if (cdist0(pi, pj)) { + (void) set_and(pt, pi, pj); + if (++T->count >= T->capacity) { + if (Tsave == NULL) + Tsave = sf_contain(T); + else + Tsave = sf_union(Tsave, sf_contain(T)); + T = new_cover(MAGIC); + pt = T->data; + } else + pt += T->wsize; + } + } + } + + + if (Tsave == NULL) + Tsave = sf_contain(T); + else + Tsave = sf_union(Tsave, sf_contain(T)); + return Tsave; +} diff --git a/benchmarks/benchmarks/espresso/sminterf.c b/benchmarks/benchmarks/espresso/sminterf.c new file mode 100644 index 0000000..96e77fa --- /dev/null +++ b/benchmarks/benchmarks/espresso/sminterf.c @@ -0,0 +1,35 @@ +#include "espresso.h" + + +pset +do_sm_minimum_cover(A) +pset_family A; +{ + sm_matrix *M; + sm_row *sparse_cover; + sm_element *pe; + pset cover; + register int i, base, rownum; + register unsigned val; + register pset last, p; + + M = sm_alloc(); + rownum = 0; + foreach_set(A, last, p) { + foreach_set_element(p, i, val, base) { + (void) sm_insert(M, rownum, base); + } + rownum++; + } + + sparse_cover = sm_minimum_cover(M, NIL(int), 1, 0); + sm_free(M); + + cover = set_new(A->sf_size); + sm_foreach_row_element(sparse_cover, pe) { + set_insert(cover, pe->col_num); + } + sm_row_free(sparse_cover); + + return cover; +} diff --git a/benchmarks/benchmarks/espresso/solution.c b/benchmarks/benchmarks/espresso/solution.c new file mode 100644 index 0000000..2222b71 --- /dev/null +++ b/benchmarks/benchmarks/espresso/solution.c @@ -0,0 +1,106 @@ +#include "espresso.h" +#include "mincov_int.h" + + +solution_t * +solution_alloc() +{ + solution_t *sol; + + sol = ALLOC(solution_t, 1); + sol->cost = 0; + sol->row = sm_row_alloc(); + return sol; +} + + +void +solution_free(sol) +solution_t *sol; +{ + sm_row_free(sol->row); + FREE(sol); +} + + +solution_t * +solution_dup(sol) +solution_t *sol; +{ + solution_t *new_sol; + + new_sol = ALLOC(solution_t, 1); + new_sol->cost = sol->cost; + new_sol->row = sm_row_dup(sol->row); + return new_sol; +} + + +void +solution_add(sol, weight, col) +solution_t *sol; +int *weight; +int col; +{ + (void) sm_row_insert(sol->row, col); + sol->cost += WEIGHT(weight, col); +} + + +void +solution_accept(sol, A, weight, col) +solution_t *sol; +sm_matrix *A; +int *weight; +int col; +{ + register sm_element *p, *pnext; + sm_col *pcol; + + solution_add(sol, weight, col); + + /* delete rows covered by this column */ + pcol = sm_get_col(A, col); + for(p = pcol->first_row; p != 0; p = pnext) { + pnext = p->next_row; /* grab it before it disappears */ + sm_delrow(A, p->row_num); + } +} + + +/* ARGSUSED */ +void +solution_reject(sol, A, weight, col) +solution_t *sol; +sm_matrix *A; +int *weight; +int col; +{ + sm_delcol(A, col); +} + + +solution_t * +solution_choose_best(best1, best2) +solution_t *best1, *best2; +{ + if (best1 != NIL(solution_t)) { + if (best2 != NIL(solution_t)) { + if (best1->cost <= best2->cost) { + solution_free(best2); + return best1; + } else { + solution_free(best1); + return best2; + } + } else { + return best1; + } + } else { + if (best2 != NIL(solution_t)) { + return best2; + } else { + return NIL(solution_t); + } + } +} diff --git a/benchmarks/benchmarks/espresso/sparse.c b/benchmarks/benchmarks/espresso/sparse.c new file mode 100644 index 0000000..559b8ca --- /dev/null +++ b/benchmarks/benchmarks/espresso/sparse.c @@ -0,0 +1,137 @@ +/* + module: sparse.c + + make_sparse is a last-step cleanup to reduce the total number + of literals in the cover. + + This is done by reducing the "sparse" variables (using a modified + version of irredundant rather than reduce), followed by expanding + the "dense" variables (using modified version of expand). +*/ + +#include "espresso.h" + +pcover make_sparse(F, D, R) +pcover F, D, R; +{ + cost_t cost, best_cost; + + cover_cost(F, &best_cost); + + do { + EXECUTE(F = mv_reduce(F, D), MV_REDUCE_TIME, F, cost); + if (cost.total == best_cost.total) + break; + copy_cost(&cost, &best_cost); + + EXECUTE(F = expand(F, R, TRUE), RAISE_IN_TIME, F, cost); + if (cost.total == best_cost.total) + break; + copy_cost(&cost, &best_cost); + } while (force_irredundant); + + return F; +} + +/* + mv_reduce -- perform an "optimal" reduction of the variables which + we desire to be sparse + + This could be done using "reduce" and then saving just the desired + part of the reduction. Instead, this version uses IRRED to find + which cubes of an output are redundant. Note that this gets around + the cube-ordering problem. + + In normal use, it is expected that the cover is irredundant and + hence no cubes will be reduced to the empty cube (however, this is + checked for and such cubes will be deleted) +*/ + +pcover +mv_reduce(F, D) +pcover F, D; +{ + register int i, var; + register pcube p, p1, last; + int index; + pcover F1, D1; + pcube *F_cube_table; + + /* loop for each multiple-valued variable */ + for(var = 0; var < cube.num_vars; var++) { + + if (cube.sparse[var]) { + + /* loop for each part of the variable */ + for(i = cube.first_part[var]; i <= cube.last_part[var]; i++) { + + /* remember mapping of F1 cubes back to F cubes */ + F_cube_table = ALLOC(pcube, F->count); + + /* 'cofactor' against part #i of variable #var */ + F1 = new_cover(F->count); + foreach_set(F, last, p) { + if (is_in_set(p, i)) { + F_cube_table[F1->count] = p; + p1 = GETSET(F1, F1->count++); + (void) set_diff(p1, p, cube.var_mask[var]); + set_insert(p1, i); + } + } + + /* 'cofactor' against part #i of variable #var */ + /* not really necessary -- just more efficient ? */ + D1 = new_cover(D->count); + foreach_set(D, last, p) { + if (is_in_set(p, i)) { + p1 = GETSET(D1, D1->count++); + (void) set_diff(p1, p, cube.var_mask[var]); + set_insert(p1, i); + } + } + + mark_irredundant(F1, D1); + + /* now remove part i from cubes which are redundant */ + index = 0; + foreach_set(F1, last, p1) { + if (! TESTP(p1, ACTIVE)) { + p = F_cube_table[index]; + + /* don't reduce a variable which is full + * (unless it is the output variable) + */ + if (var == cube.num_vars-1 || + ! setp_implies(cube.var_mask[var], p)) { + set_remove(p, i); + } + RESET(p, PRIME); + } + index++; + } + + free_cover(F1); + free_cover(D1); + FREE(F_cube_table); + } + } + } + + /* Check if any cubes disappeared */ + (void) sf_active(F); + for(var = 0; var < cube.num_vars; var++) { + if (cube.sparse[var]) { + foreach_active_set(F, last, p) { + if (setp_disjoint(p, cube.var_mask[var])) { + RESET(p, ACTIVE); + F->active_count--; + } + } + } + } + + if (F->count != F->active_count) { + F = sf_inactive(F); + } + return F; +} diff --git a/benchmarks/benchmarks/espresso/sparse.h b/benchmarks/benchmarks/espresso/sparse.h new file mode 100644 index 0000000..9c84827 --- /dev/null +++ b/benchmarks/benchmarks/espresso/sparse.h @@ -0,0 +1,126 @@ +#ifndef SPARSE_H +#define SPARSE_H + +/* + * sparse.h -- sparse matrix package header file + */ + +typedef struct sm_element_struct sm_element; +typedef struct sm_row_struct sm_row; +typedef struct sm_col_struct sm_col; +typedef struct sm_matrix_struct sm_matrix; + + +/* + * sparse matrix element + */ +struct sm_element_struct { + int row_num; /* row number of this element */ + int col_num; /* column number of this element */ + sm_element *next_row; /* next row in this column */ + sm_element *prev_row; /* previous row in this column */ + sm_element *next_col; /* next column in this row */ + sm_element *prev_col; /* previous column in this row */ + char *user_word; /* user-defined word */ +}; + + +/* + * row header + */ +struct sm_row_struct { + int row_num; /* the row number */ + int length; /* number of elements in this row */ + int flag; /* user-defined word */ + sm_element *first_col; /* first element in this row */ + sm_element *last_col; /* last element in this row */ + sm_row *next_row; /* next row (in sm_matrix linked list) */ + sm_row *prev_row; /* previous row (in sm_matrix linked list) */ + char *user_word; /* user-defined word */ +}; + + +/* + * column header + */ +struct sm_col_struct { + int col_num; /* the column number */ + int length; /* number of elements in this column */ + int flag; /* user-defined word */ + sm_element *first_row; /* first element in this column */ + sm_element *last_row; /* last element in this column */ + sm_col *next_col; /* next column (in sm_matrix linked list) */ + sm_col *prev_col; /* prev column (in sm_matrix linked list) */ + char *user_word; /* user-defined word */ +}; + + +/* + * A sparse matrix + */ +struct sm_matrix_struct { + sm_row **rows; /* pointer to row headers (by row #) */ + int rows_size; /* alloc'ed size of above array */ + sm_col **cols; /* pointer to column headers (by col #) */ + int cols_size; /* alloc'ed size of above array */ + sm_row *first_row; /* first row (linked list of all rows) */ + sm_row *last_row; /* last row (linked list of all rows) */ + int nrows; /* number of rows */ + sm_col *first_col; /* first column (linked list of columns) */ + sm_col *last_col; /* last column (linked list of columns) */ + int ncols; /* number of columns */ + char *user_word; /* user-defined word */ +}; + + +#define sm_get_col(A, colnum) \ + (((colnum) >= 0 && (colnum) < (A)->cols_size) ? \ + (A)->cols[colnum] : (sm_col *) 0) + +#define sm_get_row(A, rownum) \ + (((rownum) >= 0 && (rownum) < (A)->rows_size) ? \ + (A)->rows[rownum] : (sm_row *) 0) + +#define sm_foreach_row(A, prow) \ + for(prow = A->first_row; prow != 0; prow = prow->next_row) + +#define sm_foreach_col(A, pcol) \ + for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) + +#define sm_foreach_row_element(prow, p) \ + for(p = prow->first_col; p != 0; p = p->next_col) + +#define sm_foreach_col_element(pcol, p) \ + for(p = pcol->first_row; p != 0; p = p->next_row) + +#define sm_put(x, val) \ + (x->user_word = (char *) val) + +#define sm_get(type, x) \ + ((type) (x->user_word)) + +extern sm_matrix *sm_alloc(), *sm_alloc_size(), *sm_dup(); +extern void sm_free(), sm_delrow(), sm_delcol(), sm_resize(); +extern void sm_write(), sm_print(), sm_dump(), sm_cleanup(); +extern void sm_copy_row(), sm_copy_col(); +extern void sm_remove(), sm_remove_element(); +extern sm_element *sm_insert(), *sm_find(); +extern sm_row *sm_longest_row(); +extern sm_col *sm_longest_col(); +extern int sm_read(), sm_read_compressed(); + +extern sm_row *sm_row_alloc(), *sm_row_dup(), *sm_row_and(); +extern void sm_row_free(), sm_row_remove(), sm_row_print(); +extern sm_element *sm_row_insert(), *sm_row_find(); +extern int sm_row_contains(), sm_row_intersects(); +extern int sm_row_compare(), sm_row_hash(); + +extern sm_col *sm_col_alloc(), *sm_col_dup(), *sm_col_and(); +extern void sm_col_free(), sm_col_remove(), sm_col_print(); +extern sm_element *sm_col_insert(), *sm_col_find(); +extern int sm_col_contains(), sm_col_intersects(); +extern int sm_col_compare(), sm_col_hash(); + +extern int sm_row_dominance(), sm_col_dominance(), sm_block_partition(); + +#endif diff --git a/benchmarks/benchmarks/espresso/sparse_int.h b/benchmarks/benchmarks/espresso/sparse_int.h new file mode 100644 index 0000000..d80cfed --- /dev/null +++ b/benchmarks/benchmarks/espresso/sparse_int.h @@ -0,0 +1,110 @@ +#include "port.h" +#include "utility.h" +#include "sparse.h" + + + +/* + * sorted, double-linked list insertion + * + * type: object type + * + * first, last: fields (in header) to head and tail of the list + * count: field (in header) of length of the list + * + * next, prev: fields (in object) to link next and previous objects + * value: field (in object) which controls the order + * + * newval: value field for new object + * e: an object to use if insertion needed (set to actual value used) + */ + +#define sorted_insert(type, first, last, count, next, prev, value, newval, e) \ + if (last == 0) { \ + e->value = newval; \ + first = e; \ + last = e; \ + e->next = 0; \ + e->prev = 0; \ + count++; \ + } else if (last->value < newval) { \ + e->value = newval; \ + last->next = e; \ + e->prev = last; \ + last = e; \ + e->next = 0; \ + count++; \ + } else if (first->value > newval) { \ + e->value = newval; \ + first->prev = e; \ + e->next = first; \ + first = e; \ + e->prev = 0; \ + count++; \ + } else { \ + type *p; \ + for(p = first; p->value < newval; p = p->next) \ + ; \ + if (p->value > newval) { \ + e->value = newval; \ + p = p->prev; \ + p->next->prev = e; \ + e->next = p->next; \ + p->next = e; \ + e->prev = p; \ + count++; \ + } else { \ + e = p; \ + } \ + } + + +/* + * double linked-list deletion + */ +#define dll_unlink(p, first, last, next, prev, count) { \ + if (p->prev == 0) { \ + first = p->next; \ + } else { \ + p->prev->next = p->next; \ + } \ + if (p->next == 0) { \ + last = p->prev; \ + } else { \ + p->next->prev = p->prev; \ + } \ + count--; \ +} + + +#ifdef FAST_AND_LOOSE +extern sm_element *sm_element_freelist; +extern sm_row *sm_row_freelist; +extern sm_col *sm_col_freelist; + +#define sm_element_alloc(newobj) \ + if (sm_element_freelist == NIL(sm_element)) { \ + newobj = ALLOC(sm_element, 1); \ + } else { \ + newobj = sm_element_freelist; \ + sm_element_freelist = sm_element_freelist->next_col; \ + } \ + newobj->user_word = NIL(char); \ + +#define sm_element_free(e) \ + (e->next_col = sm_element_freelist, sm_element_freelist = e) + +#else + +#define sm_element_alloc(newobj) \ + newobj = ALLOC(sm_element, 1); \ + newobj->user_word = NIL(char); +#define sm_element_free(e) \ + FREE(e) +#endif + + +extern void sm_row_remove_element(); +extern void sm_col_remove_element(); + +/* LINTLIBRARY */ diff --git a/benchmarks/benchmarks/espresso/stdlib.h b/benchmarks/benchmarks/espresso/stdlib.h new file mode 100644 index 0000000..c5cf479 --- /dev/null +++ b/benchmarks/benchmarks/espresso/stdlib.h @@ -0,0 +1,38 @@ +/* ANSI Compatible stdlib.h stub */ + +#ifndef __cplusplus + +#include + +#ifndef ultrix4 +extern double atof(const char *); +extern int atoi(const char *); +extern long atol(const char *); +extern void abort(void); +extern void *calloc(size_t, size_t); +extern void exit(int); +extern void free(void *); +extern void *malloc(size_t); +extern void *realloc(void *, size_t); +extern char *getenv(const char *); +#else +extern double atof(const char *); +extern int atoi(char *); +extern long atol(char *); +extern void abort(void); +extern void *calloc(size_t, size_t); +extern void exit(int); +extern void free(void *); +extern void *malloc(size_t); +extern void *realloc(void *, size_t); +extern char *getenv(char *); +#endif + +/* should be in stdio.h */ +extern void perror(const char *); + +#ifdef LINT +#undef putc +#endif + +#endif diff --git a/benchmarks/benchmarks/espresso/unate.c b/benchmarks/benchmarks/espresso/unate.c new file mode 100644 index 0000000..b787c3c --- /dev/null +++ b/benchmarks/benchmarks/espresso/unate.c @@ -0,0 +1,432 @@ +/* + * unate.c -- routines for dealing with unate functions + */ + +#include "espresso.h" + +static pset_family abs_covered(); +static pset_family abs_covered_many(); +static int abs_select_restricted(); + +pcover map_cover_to_unate(T) +pcube *T; +{ + register unsigned int word_test, word_set, bit_test, bit_set; + register pcube p, pA; + pset_family A; + pcube *T1; + int ncol, i; + + A = sf_new(CUBELISTSIZE(T), cdata.vars_unate); + A->count = CUBELISTSIZE(T); + foreachi_set(A, i, p) { + (void) set_clear(p, A->sf_size); + } + ncol = 0; + + for(i = 0; i < cube.size; i++) { + if (cdata.part_zeros[i] > 0) { + assert(ncol <= cdata.vars_unate); + + /* Copy a column from T to A */ + word_test = WHICH_WORD(i); + bit_test = 1 << WHICH_BIT(i); + word_set = WHICH_WORD(ncol); + bit_set = 1 << WHICH_BIT(ncol); + + pA = A->data; + for(T1 = T+2; (p = *T1++) != 0; ) { + if ((p[word_test] & bit_test) == 0) { + pA[word_set] |= bit_set; + } + pA += A->wsize; + } + + ncol++; + } + } + + return A; +} + +pcover map_unate_to_cover(A) +pset_family A; +{ + register int i, ncol, lp; + register pcube p, pB; + int var, nunate, *unate; + pcube last; + pset_family B; + + B = sf_new(A->count, cube.size); + B->count = A->count; + + /* Find the unate variables */ + unate = ALLOC(int, cube.num_vars); + nunate = 0; + for(var = 0; var < cube.num_vars; var++) { + if (cdata.is_unate[var]) { + unate[nunate++] = var; + } + } + + /* Loop for each set of A */ + pB = B->data; + foreach_set(A, last, p) { + + /* Initialize this set of B */ + INLINEset_fill(pB, cube.size); + + /* Now loop for the unate variables; if the part is in A, + * then this variable of B should be a single 1 in the unate + * part. + */ + for(ncol = 0; ncol < nunate; ncol++) { + if (is_in_set(p, ncol)) { + lp = cube.last_part[unate[ncol]]; + for(i = cube.first_part[unate[ncol]]; i <= lp; i++) { + if (cdata.part_zeros[i] == 0) { + set_remove(pB, i); + } + } + } + } + pB += B->wsize; + } + + FREE(unate); + return B; +} + +/* + * unate_compl + */ + +pset_family unate_compl(A) +pset_family A; +{ + register pset p, last; + + /* Make sure A is single-cube containment minimal */ +/* A = sf_rev_contain(A);*/ + + foreach_set(A, last, p) { + PUTSIZE(p, set_ord(p)); + } + + /* Recursively find the complement */ + A = unate_complement(A); + + /* Now, we can guarantee a minimal result by containing the result */ + A = sf_rev_contain(A); + return A; +} + + +/* + * Assume SIZE(p) records the size of each set + */ +pset_family unate_complement(A) +pset_family A; /* disposes of A */ +{ + pset_family Abar; + register pset p, p1, restrictx; + register int i; + int max_i, min_set_ord, j; + + /* Check for no sets in the matrix -- complement is the universe */ + if (A->count == 0) { + sf_free(A); + Abar = sf_new(1, A->sf_size); + (void) set_clear(GETSET(Abar, Abar->count++), A->sf_size); + + /* Check for a single set in the maxtrix -- compute de Morgan complement */ + } else if (A->count == 1) { + p = A->data; + Abar = sf_new(A->sf_size, A->sf_size); + for(i = 0; i < A->sf_size; i++) { + if (is_in_set(p, i)) { + p1 = set_clear(GETSET(Abar, Abar->count++), A->sf_size); + set_insert(p1, i); + } + } + sf_free(A); + + } else { + + /* Select splitting variable as the variable which belongs to a set + * of the smallest size, and which has greatest column count + */ + restrictx = set_new(A->sf_size); + min_set_ord = A->sf_size + 1; + foreachi_set(A, i, p) { + if (SIZE(p) < min_set_ord) { + set_copy(restrictx, p); + min_set_ord = SIZE(p); + } else if (SIZE(p) == min_set_ord) { + set_or(restrictx, restrictx, p); + } + } + + /* Check for no data (shouldn't happen ?) */ + if (min_set_ord == 0) { + A->count = 0; + Abar = A; + + /* Check for "essential" columns */ + } else if (min_set_ord == 1) { + Abar = unate_complement(abs_covered_many(A, restrictx)); + sf_free(A); + foreachi_set(Abar, i, p) { + set_or(p, p, restrictx); + } + + /* else, recur as usual */ + } else { + max_i = abs_select_restricted(A, restrictx); + + /* Select those rows of A which are not covered by max_i, + * recursively find all minimal covers of these rows, and + * then add back in max_i + */ + Abar = unate_complement(abs_covered(A, max_i)); + foreachi_set(Abar, i, p) { + set_insert(p, max_i); + } + + /* Now recur on A with all zero's on column max_i */ + foreachi_set(A, i, p) { + if (is_in_set(p, max_i)) { + set_remove(p, max_i); + j = SIZE(p) - 1; + PUTSIZE(p, j); + } + } + + Abar = sf_append(Abar, unate_complement(A)); + } + set_free(restrictx); + } + + return Abar; +} + +pset_family exact_minimum_cover(T) +IN pset_family T; +{ + register pset p, last, p1; + register int i, n; + int lev, lvl; + pset nlast; + pset_family temp; + long start = ptime(); + struct { + pset_family sf; + int level; + } stack[32]; /* 32 suffices for 2 ** 32 cubes ! */ + + if (T->count <= 0) + return sf_new(1, T->sf_size); + for(n = T->count, lev = 0; n != 0; n >>= 1, lev++) ; + + /* A simple heuristic ordering */ + T = lex_sort(sf_save(T)); + + /* Push a full set on the stack to get things started */ + n = 1; + stack[0].sf = sf_new(1, T->sf_size); + stack[0].level = lev; + set_fill(GETSET(stack[0].sf, stack[0].sf->count++), T->sf_size); + + nlast = GETSET(T, T->count - 1); + foreach_set(T, last, p) { + + /* "unstack" the set into a family */ + temp = sf_new(set_ord(p), T->sf_size); + for(i = 0; i < T->sf_size; i++) + if (is_in_set(p, i)) { + p1 = set_fill(GETSET(temp, temp->count++), T->sf_size); + set_remove(p1, i); + } + stack[n].sf = temp; + stack[n++].level = lev; + + /* Pop the stack and perform (leveled) intersections */ + while (n > 1 && (stack[n-1].level==stack[n-2].level || p == nlast)) { + temp = unate_intersect(stack[n-1].sf, stack[n-2].sf, FALSE); + lvl = MIN(stack[n-1].level, stack[n-2].level) - 1; + if (debug & MINCOV && lvl < 10) { + printf("# EXACT_MINCOV[%d]: %4d = %4d x %4d, time = %s\n", + lvl, temp->count, stack[n-1].sf->count, + stack[n-2].sf->count, print_time(ptime() - start)); + (void) fflush(stdout); + } + sf_free(stack[n-2].sf); + sf_free(stack[n-1].sf); + stack[n-2].sf = temp; + stack[n-2].level = lvl; + n--; + } + } + + temp = stack[0].sf; + p1 = set_fill(set_new(T->sf_size), T->sf_size); + foreach_set(temp, last, p) + INLINEset_diff(p, p1, p); + set_free(p1); + if (debug & MINCOV1) { + printf("MINCOV: family of all minimal coverings is\n"); + sf_print(temp); + } + sf_free(T); /* this is the copy of T we made ... */ + return temp; +} + +/* + * unate_intersect -- intersect two unate covers + * + * If largest_only is TRUE, then only the largest cube(s) are returned + */ + +#define MAGIC 500 /* save 500 cubes before containment */ + +pset_family unate_intersect(A, B, largest_only) +pset_family A, B; +bool largest_only; +{ + register pset pi, pj, lasti, lastj, pt; + pset_family T, Tsave; + bool save; + int maxord, ord; + + /* How large should each temporary result cover be ? */ + T = sf_new(MAGIC, A->sf_size); + Tsave = NULL; + maxord = 0; + pt = T->data; + + /* Form pairwise intersection of each set of A with each cube of B */ + foreach_set(A, lasti, pi) { + + foreach_set(B, lastj, pj) { + + save = set_andp(pt, pi, pj); + + /* Check if we want the largest only */ + if (save && largest_only) { + if ((ord = set_ord(pt)) > maxord) { + /* discard Tsave and T */ + if (Tsave != NULL) { + sf_free(Tsave); + Tsave = NULL; + } + pt = T->data; + T->count = 0; + /* Re-create pt (which was just thrown away) */ + (void) set_and(pt, pi, pj); + maxord = ord; + } else if (ord < maxord) { + save = FALSE; + } + } + + if (save) { + if (++T->count >= T->capacity) { + T = sf_contain(T); + Tsave = (Tsave == NULL) ? T : sf_union(Tsave, T); + T = sf_new(MAGIC, A->sf_size); + pt = T->data; + } else { + pt += T->wsize; + } + } + } + } + + + /* Contain the final result and merge it into Tsave */ + T = sf_contain(T); + Tsave = (Tsave == NULL) ? T : sf_union(Tsave, T); + + return Tsave; +} + +/* + * abs_covered -- after selecting a new column for the selected set, + * create a new matrix which is only those rows which are still uncovered + */ +static pset_family +abs_covered(A, pick) +pset_family A; +register int pick; +{ + register pset last, p, pdest; + register pset_family Aprime; + + Aprime = sf_new(A->count, A->sf_size); + pdest = Aprime->data; + foreach_set(A, last, p) + if (! is_in_set(p, pick)) { + INLINEset_copy(pdest, p); + Aprime->count++; + pdest += Aprime->wsize; + } + return Aprime; +} + + +/* + * abs_covered_many -- after selecting many columns for ther selected set, + * create a new matrix which is only those rows which are still uncovered + */ +static pset_family +abs_covered_many(A, pick_set) +pset_family A; +register pset pick_set; +{ + register pset last, p, pdest; + register pset_family Aprime; + + Aprime = sf_new(A->count, A->sf_size); + pdest = Aprime->data; + foreach_set(A, last, p) + if (setp_disjoint(p, pick_set)) { + INLINEset_copy(pdest, p); + Aprime->count++; + pdest += Aprime->wsize; + } + return Aprime; +} + + +/* + * abs_select_restricted -- select the column of maximum column count which + * also belongs to the set "restrictx"; weight each column of a set as + * 1 / (set_ord(p) - 1). + */ +static int +abs_select_restricted(A, restrictx) +pset_family A; +pset restrictx; +{ + register int i, best_var, best_count, *count; + + /* Sum the elements in these columns */ + count = sf_count_restricted(A, restrictx); + + /* Find which variable has maximum weight */ + best_var = -1; + best_count = 0; + for(i = 0; i < A->sf_size; i++) { + if (count[i] > best_count) { + best_var = i; + best_count = count[i]; + } + } + FREE(count); + + if (best_var == -1) + fatal("abs_select_restricted: should not have best_var == -1"); + + return best_var; +} diff --git a/benchmarks/benchmarks/espresso/utility.c b/benchmarks/benchmarks/espresso/utility.c new file mode 100644 index 0000000..3c140a1 --- /dev/null +++ b/benchmarks/benchmarks/espresso/utility.c @@ -0,0 +1,162 @@ +/* LINTLIBRARY */ +#include "espresso.h" +#include "copyright.h" +#include "port.h" +#include "utility.h" + +#ifdef IBM_WATC /* IBM Waterloo-C compiler (same as bsd 4.2) */ +#ifndef BSD +#define BSD +#endif +#ifndef void +#define void int +#endif +#endif + +#ifdef ultrix +#ifndef BSD +#define BSD +#endif +#endif + +#ifdef hpux +#ifndef UNIX50 +#define UNIX50 +#endif +#endif + +#ifdef aiws +#ifndef UNIX10 +#define UNIX10 +#endif +#endif + +#ifdef vms /* VAX/C compiler -- times() with 100 HZ clock */ +#ifndef UNIX100 +#define UNIX100 +#endif +#endif + +/* default */ +#if !defined(BSD) && !defined(UNIX10) && !defined(UNIX60) && !defined(UNIX100) && !defined(UNIX50) && !defined(_WIN32) +#define UNIX10 +#endif + +#ifdef BSD +#include +#include +#endif + +#ifdef UNIX10 +#include +#endif + +#ifdef UNIX50 +#include +#endif + +#ifdef UNIX60 +#include +#endif + +#ifdef UNIX100 +#include +#endif + +#ifdef _MSC_VER +#include +#include +#endif + +/* + * util_cpu_time -- return a long which represents the elapsed processor + * time in milliseconds since some constant reference + */ +long +util_cpu_time() +{ + long t = 0; + +#ifdef _MSC_VER + static uint64_t frec = 0; + if (frec == 0) + { + LARGE_INTEGER val; + BOOL ok = QueryPerformanceFrequency(&val); + assert(ok); + frec = val.QuadPart / 1000; + } + LARGE_INTEGER val; + BOOL ok = QueryPerformanceCounter(&val); + assert(ok); + t = val.QuadPart / frec; +#endif + +#ifdef BSD + struct rusage rusage; + (void) getrusage(RUSAGE_SELF, &rusage); + t = (long) rusage.ru_utime.tv_sec*1000 + rusage.ru_utime.tv_usec/1000; +#endif + +#ifdef IBMPC + long ltime; + (void) time(<ime); + t = ltime * 1000; +#endif + +#ifdef UNIX10 /* times() with 10 Hz resolution */ + struct tms buffer; + (void) times(&buffer); + t = buffer.tms_utime * 100; +#endif + +#ifdef UNIX50 /* times() with 50 Hz resolution */ + struct tms buffer; + times(&buffer); + t = buffer.tms_utime * 20; +#endif + +#ifdef UNIX60 /* times() with 60 Hz resolution */ + struct tms buffer; + times(&buffer); + t = buffer.tms_utime * 16.6667; +#endif + +#ifdef UNIX100 + struct tms buffer; /* times() with 100 Hz resolution */ + times(&buffer); + t = buffer.tms_utime * 10; +#endif + + return t; +} + + +/* + * util_print_time -- massage a long which represents a time interval in + * milliseconds, into a string suitable for output + * + * Hack for IBM/PC -- avoids using floating point + */ + +char * +util_print_time(t) +long t; +{ + static char s[40]; + + //(void) sprintf(s, "%ld.%02ld sec", 0/1000, (0%1000)/10); + (void) sprintf(s, "%ld.%03ld sec", t/1000, (t%1000)); + return s; +} + + +/* + * util_strsav -- save a copy of a string + */ +char * +util_strsav(s) +char *s; +{ + return strcpy(ALLOC(char, strlen(s)+1), s); +} diff --git a/benchmarks/benchmarks/espresso/utility.h b/benchmarks/benchmarks/espresso/utility.h new file mode 100644 index 0000000..dcb834e --- /dev/null +++ b/benchmarks/benchmarks/espresso/utility.h @@ -0,0 +1,93 @@ +#ifndef UTILITY_H +#define UTILITY_H + +#include +#include +//#include + +/* + * assumes the memory manager is libmm.a + * - allows malloc(0) or realloc(obj, 0) + * - catches out of memory (and calls MMout_of_memory()) + * - catch free(0) and realloc(0, size) in the macros + */ +#define NIL(type) ((type *) 0) + +#ifdef BWGC +#define ALLOC(type, num) \ + ((type *) gc_malloc(sizeof(type) * ((num)==0?1:(num)))) +#define REALLOC(type, obj, num) \ + (obj) ? ((type *) gc_realloc((char *) obj, sizeof(type) * ((num)==0?1:(num)))) : \ + ((type *) gc_malloc(sizeof(type) * ((num)==0?1:(num)))) +#elif defined(CUSTOM_MALLOC) +#define ALLOC(type, num) \ + ((type *) CUSTOM_MALLOC(sizeof(type) * (num))) +#define REALLOC(type, obj, num) \ + (obj) ? ((type *) CUSTOM_REALLOC((char *) obj, sizeof(type) * (num))) : \ + ((type *) CUSTOM_MALLOC(sizeof(type) * (num))) +#else +#include +#define ALLOC(type, num) \ + ((type *) malloc(sizeof(type) * (num))) +#define REALLOC(type, obj, num) \ + (obj) ? ((type *) realloc((char *) obj, sizeof(type) * (num))) : \ + ((type *) malloc(sizeof(type) * (num))) +#endif + +#ifdef IGNOREFREE +#define FREE(obj) \ + {}; +#elif defined(CUSTOM_FREE) +#define FREE(obj) \ + if ((obj)) { (void) CUSTOM_FREE((char *) (obj)); (obj) = 0; } +#else +#define FREE(obj) \ + if ((obj)) { (void) free((char *) (obj)); (obj) = 0; } +#endif + +#include "ansi.h" + +EXTERN long util_cpu_time + NULLARGS; +EXTERN char *util_path_search + ARGS((char *program)); +EXTERN char *util_file_search + ARGS((char *file, char *path, char *mode)); +EXTERN int util_pipefork + ARGS((char **argv, FILE **toCommand, FILE **fromCommand, int *pid)); +EXTERN int util_csystem + ARGS((char *command)); +EXTERN char *util_print_time + ARGS((long t)); +EXTERN char *util_strsav + ARGS((char *ptr)); +EXTERN char *util_tilde_expand + ARGS((char *filename)); +EXTERN char *util_tilde_compress + ARGS((char *filename)); +EXTERN void util_register_user + ARGS((char *user, char *directory)); + +#ifndef NIL_FN +#define NIL_FN(type) ((type (*)()) 0) +#endif /* NIL_FN */ + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif /* MAX */ +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif /* MIN */ +#ifndef ABS +#define ABS(a) ((a) > 0 ? (a) : -(a)) +#endif /* ABS */ + + +#ifdef lint +#undef ALLOC /* allow for lint -h flag */ +#undef REALLOC +#define ALLOC(type, num) (((type *) 0) + (num)) +#define REALLOC(type, obj, num) ((obj) + (num)) +#endif /* lint */ + +#endif diff --git a/benchmarks/benchmarks/espresso/verify.c b/benchmarks/benchmarks/espresso/verify.c new file mode 100644 index 0000000..3cecd8b --- /dev/null +++ b/benchmarks/benchmarks/espresso/verify.c @@ -0,0 +1,184 @@ +/* + */ + +#include "espresso.h" + +/* + * verify -- check that all minterms of F are contained in (Fold u Dold) + * and that all minterms of Fold are contained in (F u Dold). + */ +bool verify(F, Fold, Dold) +pcover F, Fold, Dold; +{ + pcube p, last, *FD; + bool verify_error = FALSE; + + /* Make sure the function didn't grow too large */ + FD = cube2list(Fold, Dold); + foreach_set(F, last, p) + if (! cube_is_covered(FD, p)) { + printf("some minterm in F is not covered by Fold u Dold\n"); + verify_error = TRUE; + if (verbose_debug) printf("%s\n", pc1(p)); else break; + } + free_cubelist(FD); + + /* Make sure minimized function covers the original function */ + FD = cube2list(F, Dold); + foreach_set(Fold, last, p) + if (! cube_is_covered(FD, p)) { + printf("some minterm in Fold is not covered by F u Dold\n"); + verify_error = TRUE; + if (verbose_debug) printf("%s\n", pc1(p)); else break; + } + free_cubelist(FD); + + return verify_error; +} + + + +/* + * PLA_verify -- verify that two PLA's are identical + * + * If names are given, row and column permutations are done to make + * the comparison meaningful. + * + */ +bool PLA_verify(PLA1, PLA2) +pPLA PLA1, PLA2; +{ + /* Check if both have names given; if so, attempt to permute to + * match the names + */ + if (PLA1->label != NULL && PLA1->label[0] != NULL && + PLA2->label != NULL && PLA2->label[0] != NULL) { + PLA_permute(PLA1, PLA2); + } else { + fprintf(stderr, "Warning: cannot permute columns without names\n"); + return TRUE; + } + + if (PLA1->F->sf_size != PLA2->F->sf_size) { + fprintf(stderr, "PLA_verify: PLA's are not the same size\n"); + return TRUE; + } + + return verify(PLA2->F, PLA1->F, PLA1->D); +} + + + +/* + * Permute the columns of PLA1 so that they match the order of PLA2 + * Discard any columns of PLA1 which are not in PLA2 + * Association is strictly by the names of the columns of the cover. + */ +PLA_permute(PLA1, PLA2) +pPLA PLA1, PLA2; +{ + register int i, j, *permute, npermute; + register char *labi; + char **label; + + /* determine which columns of PLA1 to save, and place these in the list + * "permute"; the order in this list is the final output order + */ + npermute = 0; + permute = ALLOC(int, PLA2->F->sf_size); + for(i = 0; i < PLA2->F->sf_size; i++) { + labi = PLA2->label[i]; + for(j = 0; j < PLA1->F->sf_size; j++) { + if (strcmp(labi, PLA1->label[j]) == 0) { + permute[npermute++] = j; + break; + } + } + } + + /* permute columns */ + if (PLA1->F != NULL) { + PLA1->F = sf_permute(PLA1->F, permute, npermute); + } + if (PLA1->R != NULL) { + PLA1->R = sf_permute(PLA1->R, permute, npermute); + } + if (PLA1->D != NULL) { + PLA1->D = sf_permute(PLA1->D, permute, npermute); + } + + /* permute the labels */ + label = ALLOC(char *, cube.size); + for(i = 0; i < npermute; i++) { + label[i] = PLA1->label[permute[i]]; + } + for(i = npermute; i < cube.size; i++) { + label[i] = NULL; + } + FREE(PLA1->label); + PLA1->label = label; + + FREE(permute); +} + + + +/* + * check_consistency -- test that the ON-set, OFF-set and DC-set form + * a partition of the boolean space. + */ +bool check_consistency(PLA) +pPLA PLA; +{ + bool verify_error = FALSE; + pcover T; + + T = cv_intersect(PLA->F, PLA->D); + if (T->count == 0) + printf("ON-SET and DC-SET are disjoint\n"); + else { + printf("Some minterm(s) belong to both the ON-SET and DC-SET !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + } + (void) fflush(stdout); + free_cover(T); + + T = cv_intersect(PLA->F, PLA->R); + if (T->count == 0) + printf("ON-SET and OFF-SET are disjoint\n"); + else { + printf("Some minterm(s) belong to both the ON-SET and OFF-SET !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + } + (void) fflush(stdout); + free_cover(T); + + T = cv_intersect(PLA->D, PLA->R); + if (T->count == 0) + printf("DC-SET and OFF-SET are disjoint\n"); + else { + printf("Some minterm(s) belong to both the OFF-SET and DC-SET !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + } + (void) fflush(stdout); + free_cover(T); + + if (tautology(cube3list(PLA->F, PLA->D, PLA->R))) + printf("Union of ON-SET, OFF-SET and DC-SET is the universe\n"); + else { + T = complement(cube3list(PLA->F, PLA->D, PLA->R)); + printf("There are minterms left unspecified !\n"); + if (verbose_debug) + cprint(T); + verify_error = TRUE; + free_cover(T); + } + (void) fflush(stdout); + return verify_error; +} diff --git a/benchmarks/benchmarks/xmalloc-test/README.md b/benchmarks/benchmarks/xmalloc-test/README.md new file mode 100644 index 0000000..7f69efb --- /dev/null +++ b/benchmarks/benchmarks/xmalloc-test/README.md @@ -0,0 +1,17 @@ +xmalloc-test.c: is also known as "malloc-test" + +Originally by C. Lever and D. Boreham, Christian Eder ( ederc@mathematik.uni-kl.de) for [xmalloc](https://github.com/ederc/xmalloc), +and modified by Bradley C. Kuzmaul for SuperMalloc + +``` +* \author C. Lever and D. Boreham, Christian Eder ( ederc@mathematik.uni-kl.de ) +* \date 2000 +* \brief Test file for xmalloc. This is a multi-threaded test system by +* Lever and Boreham. It is first noted in their paper "malloc() +* Performance in a Multithreaded Linux Environment", appeared at the +* USENIX 2000 Annual Technical Conference: FREENIX Track. +* This file is part of XMALLOC, licensed under the GNU General +* Public License version 3. See COPYING for more information. +``` + +Random.h is based on lran2.h by Wolfram Gloger 1996 diff --git a/benchmarks/benchmarks/xmalloc-test/random.h b/benchmarks/benchmarks/xmalloc-test/random.h new file mode 100644 index 0000000..8577ff9 --- /dev/null +++ b/benchmarks/benchmarks/xmalloc-test/random.h @@ -0,0 +1,49 @@ +// ======================================================= + +/* lran2.h + * by Wolfram Gloger 1996. + * + * A small, portable pseudo-random number generator. + */ + +#ifndef _LRAN2_H +#define _LRAN2_H + +#define LRAN2_MAX 714025l /* constants for portable */ +#define IA 1366l /* random number generator */ +#define IC 150889l /* (see e.g. `Numerical Recipes') */ + +struct lran2_st { + long x, y, v[97]; +}; + +static void +lran2_init(struct lran2_st* d, long seed) +{ + long x; + int j; + + x = (IC - seed) % LRAN2_MAX; + if(x < 0) x = -x; + for(j=0; j<97; j++) { + x = (IA*x + IC) % LRAN2_MAX; + d->v[j] = x; + } + d->x = (IA*x + IC) % LRAN2_MAX; + d->y = d->x; +} + +static +long lran2(struct lran2_st* d) +{ + int j = (d->y % 97); + + d->y = d->v[j]; + d->x = (IA*d->x + IC) % LRAN2_MAX; + d->v[j] = d->x; + return d->y; +} + +#undef IA +#undef IC +#endif diff --git a/benchmarks/benchmarks/xmalloc-test/xmalloc-test.c b/benchmarks/benchmarks/xmalloc-test/xmalloc-test.c new file mode 100644 index 0000000..b7403f1 --- /dev/null +++ b/benchmarks/benchmarks/xmalloc-test/xmalloc-test.c @@ -0,0 +1,287 @@ +/** + * \file test-malloc_test.c + * \author C. Lever and D. Boreham, Christian Eder ( ederc@mathematik.uni-kl.de ) + * \date 2000 + * \brief Test file for xmalloc. This is a multi-threaded test system by + * Lever and Boreham. It is first noted in their paper "malloc() + * Performance in a Multithreaded Linux Environment", appeared at the + * USENIX 2000 Annual Technical Conference: FREENIX Track. + * This file is part of XMALLOC, licensed under the GNU General + * Public License version 3. See COPYING for more information. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include "xmalloc-config.h" +//#include "xmalloc.h" + +#include "random.h" + +#define CACHE_ALIGNED 1 + +#define xmalloc malloc +#define xfree free + +#define DEFAULT_OBJECT_SIZE 1024 + +int debug_flag = 0; +int verbose_flag = 0; +#define num_workers_default 4 +int num_workers = num_workers_default; +double run_time = 5.0; +int object_size = DEFAULT_OBJECT_SIZE; +/* array for thread ids */ +pthread_t *thread_ids; +/* array for saving result of each thread */ +struct counter { + long c +#if CACHE_ALIGNED + __attribute__((aligned(64))) +#endif +; +}; +struct counter *counters; + +volatile int done_flag = 0; +struct timeval begin; + + +#define atomic_load(addr) __atomic_load_n(addr, __ATOMIC_CONSUME) +#define atomic_store(addr, v) __atomic_store_n(addr, v, __ATOMIC_RELEASE) + + +static void +tvsub(tdiff, t1, t0) + struct timeval *tdiff, *t1, *t0; +{ + + tdiff->tv_sec = t1->tv_sec - t0->tv_sec; + tdiff->tv_usec = t1->tv_usec - t0->tv_usec; + if (tdiff->tv_usec < 0) + tdiff->tv_sec--, tdiff->tv_usec += 1000000; +} + +double elapsed_time(struct timeval *time0) +{ + struct timeval timedol; + struct timeval td; + double et = 0.0; + + gettimeofday(&timedol, (struct timezone *)0); + tvsub( &td, &timedol, time0 ); + et = td.tv_sec + ((double)td.tv_usec) / 1000000; + + return( et ); +} + +static const long possible_sizes[] = {8,12,16,24,32,48,64,96,128,192,256,(256*3)/2,512, (512*3)/2, 1024, (1024*3)/2, 2048}; +static const int n_sizes = sizeof(possible_sizes)/sizeof(long); + +#define OBJECTS_PER_BATCH 4096 +struct batch { + struct batch *next_batch; + void *objects[OBJECTS_PER_BATCH]; +}; + +volatile struct batch *batches = NULL; +volatile int batch_count = 0; +const int batch_count_limit = 100; +pthread_cond_t empty_cv = PTHREAD_COND_INITIALIZER; +pthread_cond_t full_cv = PTHREAD_COND_INITIALIZER; +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +void enqueue_batch(struct batch *batch) { + pthread_mutex_lock(&lock); + while (batch_count >= batch_count_limit && !atomic_load(&done_flag)) { + pthread_cond_wait(&full_cv, &lock); + } + batch->next_batch = batches; + batches = batch; + batch_count++; + pthread_cond_signal(&empty_cv); + pthread_mutex_unlock(&lock); +} + +struct batch* dequeue_batch() { + pthread_mutex_lock(&lock); + while (batches == NULL && !atomic_load(&done_flag)) { + pthread_cond_wait(&empty_cv, &lock); + } + struct batch* result = batches; + if (result) { + batches = result->next_batch; + batch_count--; + pthread_cond_signal(&full_cv); + } + pthread_mutex_unlock(&lock); + return result; +} + +void *mem_allocator (void *arg) { + int thread_id = *(int *)arg; + struct lran2_st lr; + lran2_init(&lr, thread_id); + + while (!atomic_load(&done_flag)) { + struct batch *b = xmalloc(sizeof(*b)); + for (int i = 0; i < OBJECTS_PER_BATCH; i++) { + size_t siz = object_size > 0 ? object_size : possible_sizes[lran2(&lr)%n_sizes]; + b->objects[i] = xmalloc(siz); + memset(b->objects[i],i%256,(siz > 128 ? 128 : siz)); + } + enqueue_batch(b); + } + return NULL; +} + +void *mem_releaser(void *arg) { + int thread_id = *(int *)arg; + + while(!atomic_load(&done_flag)) { + struct batch *b = dequeue_batch(); + if (b) { + for (int i = 0; i < OBJECTS_PER_BATCH; i++) { + xfree(b->objects[i]); + } + xfree(b); + } + counters[thread_id].c += OBJECTS_PER_BATCH; + } + return NULL; +} + +int run_memory_free_test() +{ + void *ptr = NULL; + int i; + double elapse_time = 0.0; + long total = 0; + int *ids = (int *)xmalloc(sizeof(int) * num_workers); + + /* Initialize counter */ + for(i = 0; i < num_workers; ++i) + counters[i].c = 0; + + gettimeofday(&begin, (struct timezone *)0); + + /* Start up the mem_allocator and mem_releaser threads */ + for(i = 0; i < num_workers; ++i) { + ids[i] = i; + if (verbose_flag) printf("Starting mem_releaser %i ...\n", i); + if (pthread_create(&thread_ids[i * 2], NULL, mem_releaser, (void *)&ids[i])) { + perror("pthread_create mem_releaser"); + exit(errno); + } + + if (verbose_flag) printf("Starting mem_allocator %i ...\n", i); + if (pthread_create(&thread_ids[i * 2 + 1], NULL, mem_allocator, (void *)&ids[i])) { + perror("pthread_create mem_allocator"); + exit(errno); + } + } + + if (verbose_flag) printf("Testing for %.2f seconds\n\n", run_time); + + while (1) { + usleep(1000); + if (elapsed_time(&begin) > run_time) { + atomic_store(&done_flag, 1); + pthread_cond_broadcast(&empty_cv); + pthread_cond_broadcast(&full_cv); + break; + } + } + + for(i = 0; i < num_workers * 2; ++i) + pthread_join (thread_ids[i], &ptr); + + elapse_time = elapsed_time (&begin); + + for(i = 0; i < num_workers; ++i) { + if (verbose_flag) { + printf("Thread %2i frees %ld blocks in %.2f seconds. %.2f free/sec.\n", + i, counters[i].c, elapse_time, ((double)counters[i].c/elapse_time)); + } + } + if (verbose_flag) printf("----------------------------------------------------------------\n"); + for(i = 0; i < num_workers; ++i) total += counters[i].c; + if (verbose_flag) + printf("Total %ld freed in %.2f seconds. %.2fM free/second\n", + total, elapse_time, ((double) total/elapse_time)*1e-6); + else { + double mfree_per_sec = ((double)total/elapse_time) * 1e-6; + double rtime = 100.0 / mfree_per_sec; + printf("rtime: %.3f, free/sec: %.3f M\n", rtime, mfree_per_sec); + } + if (verbose_flag) printf("Program done\n"); + if (ids!=NULL) xfree(ids); + return(0); +} + +void usage(char *prog) +{ + printf("%s [-w workers] [-t run_time] [-d] [-v]\n", prog); + printf("\t -w number of producer threads (and number of consumer threads), default %d\n", num_workers_default); + printf("\t -t run time in seconds, default 20.0 seconds.\n"); + printf("\t -s size of object to allocate (default %d bytes) (specify -1 to get many different object sizes)\n", DEFAULT_OBJECT_SIZE); + printf("\t -d debug mode\n"); + printf("\t -v verbose mode (-v -v produces more verbose)\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + int c; + while ((c = getopt(argc, argv, "w:t:ds:v")) != -1) { + + switch (c) { + + case 'w': + num_workers = atoi(optarg); + break; + case 't': + run_time = atof(optarg); + break; + case 'd': + debug_flag = 1; + break; + case 's': + object_size = atoi(optarg); + break; + case 'v': + verbose_flag++; + break; + default: + usage(argv[0]); + } + } + + /* allocate memory for working arrays */ + thread_ids = (pthread_t *) xmalloc(sizeof(pthread_t) * num_workers * 2); + counters = (struct counter *) xmalloc(sizeof(*counters) * num_workers); + + run_memory_free_test(); + + while (batches) { + struct batch *b = batches; + batches = b->next_batch; + for (int i = 0 ; i < OBJECTS_PER_BATCH; i++) { + xfree(b->objects[i]); + } + xfree(b); + } + + xfree(thread_ids); + xfree(counters); + + return 0; +}