added more allocator benchmarks

This commit is contained in:
2024-12-03 18:58:22 +00:00
parent 81397da55e
commit c9ba5e5d8c
128 changed files with 27846 additions and 2149 deletions

View File

@@ -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;
}

View File

@@ -1,123 +0,0 @@
#include "XSbench_header.h"
#ifdef MPI
#include<mpi.h>
#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;
}

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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 <optimized variant ID>" 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 <optimized variant ID>" 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)<cutoff) ){
if (left < j){ quickSort_parallel_internal_i_d(key, value, left, j, cutoff); }
if (i < right){ quickSort_parallel_internal_i_d(key, value, i, right, cutoff); }
}else{
#pragma omp task
{ quickSort_parallel_internal_i_d(key, value, left, j, cutoff); }
#pragma omp task
{ quickSort_parallel_internal_i_d(key, value, i, right, cutoff); }
}
}
void quickSort_parallel_i_d(int* key,double * value, int lenArray, int numThreads){
// Set minumum problem size to still spawn threads for
int cutoff = 10000;
// For this problem size, more than 16 threads on CPU is not helpful
if( numThreads > 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)<cutoff) ){
if (left < j){ quickSort_parallel_internal_d_i(key, value, left, j, cutoff); }
if (i < right){ quickSort_parallel_internal_d_i(key, value, i, right, cutoff); }
}else{
#pragma omp task
{ quickSort_parallel_internal_d_i(key, value, left, j, cutoff); }
#pragma omp task
{ quickSort_parallel_internal_d_i(key, value, i, right, cutoff); }
}
}
void quickSort_parallel_d_i(double* key,int * value, int lenArray, int numThreads){
// Set minumum problem size to still spawn threads for
int cutoff = 10000;
// For this problem size, more than 16 threads on CPU is not helpful
if( numThreads > 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;
}

View File

@@ -1,151 +0,0 @@
#ifndef __XSBENCH_HEADER_H__
#define __XSBENCH_HEADER_H__
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#include<math.h>
#include<assert.h>
#include<stdint.h>
#ifdef _MSC_VER
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#else
#include<unistd.h>
#include<sys/time.h>
#endif
#ifdef OPENMP
#include<omp.h>
#endif
// Papi Header
#ifdef PAPI
#include "papi.h"
#endif
//AML header
#ifdef AML
#include<aml.h>
#include<aml/higher/replicaset.h>
#include<aml/higher/replicaset/hwloc.h>
#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

View File

@@ -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;
}

View File

@@ -1,508 +0,0 @@
#include "XSbench_header.h"
#ifdef MPI
#include<mpi.h>
#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 <options>\n");
printf("Options include:\n");
printf(" -m <simulation method> Simulation method (history, event)\n");
printf(" -t <threads> Number of OpenMP threads to run\n");
printf(" -s <size> Size of H-M Benchmark to run (small, large, XL, XXL)\n");
printf(" -g <gridpoints> Number of gridpoints per nuclide (overrides -s defaults)\n");
printf(" -G <grid type> Grid search type (unionized, nuclide, hash). Defaults to unionized.\n");
printf(" -p <particles> Number of particle histories\n");
printf(" -l <lookups> History Based: Number of Cross-section (XS) lookups per particle. Event Based: Total number of XS lookups.\n");
printf(" -h <hash bins> Number of hash bins (only relevant when used with \"-G hash\")\n");
printf(" -b <binary mode> Read or write all data structures to file. If reading, this will skip initialization phase. (read, write)\n");
printf(" -k <kernel ID> 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;
}

View File

@@ -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 <https://github.com/node-dot-cpp/alloc-test>.
```
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 <organization> 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 <COPYRIGHT HOLDER> 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.
```

View File

@@ -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 <organization> 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 <COPYRIGHT HOLDER> 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<class Allocator>
void* runRandomTest( void* params )
{
assert( params != nullptr );
ThreadStartupParamsAndResults* testParams = reinterpret_cast<ThreadStartupParamsAndResults*>( params );
Allocator allocator( testParams->threadRes );
switch ( testParams->startupParams.mat )
{
case MEM_ACCESS_TYPE::none:
randomPos_RandomSize<Allocator,MEM_ACCESS_TYPE::none>( allocator, testParams->startupParams.iterCount, testParams->startupParams.maxItems, testParams->startupParams.maxItemSize, testParams->threadID, testParams->startupParams.rndSeed );
break;
case MEM_ACCESS_TYPE::full:
randomPos_RandomSize<Allocator,MEM_ACCESS_TYPE::full>( allocator, testParams->startupParams.iterCount, testParams->startupParams.maxItems, testParams->startupParams.maxItemSize, testParams->threadID, testParams->startupParams.rndSeed );
break;
case MEM_ACCESS_TYPE::single:
randomPos_RandomSize<Allocator,MEM_ACCESS_TYPE::single>( allocator, testParams->startupParams.iterCount, testParams->startupParams.maxItems, testParams->startupParams.maxItemSize, testParams->threadID, testParams->startupParams.rndSeed );
break;
case MEM_ACCESS_TYPE::check:
randomPos_RandomSize<Allocator,MEM_ACCESS_TYPE::check>( allocator, testParams->startupParams.iterCount, testParams->startupParams.maxItems, testParams->startupParams.maxItemSize, testParams->threadID, testParams->startupParams.rndSeed );
break;
}
return nullptr;
}
template<class Allocator>
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; i<threadCount; ++i )
{
memcpy( testParams + i, startupParams, sizeof(TestStartupParams) );
testParams[i].threadID = i;
testParams[i].threadRes = startupParams->testRes->threadRes + i;
}
// run threads
for ( size_t i=0; i<threadCount; ++i )
{
printf( "about to run thread %zd...\n", i );
std::thread t1( runRandomTest<Allocator>, (void*)(testParams + i) );
threads[i] = std::move( t1 );
printf( " ...done\n" );
}
// join threads
for ( size_t i=0; i<threadCount; ++i )
{
printf( "joining thread %zd...\n", i );
threads[i].join();
printf( " ...done\n" );
}
size_t end = GetMillisecondCount();
startupParams->testRes->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; i<threadCount; ++i )
{
startupParams->testRes->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<MyAllocatorT>( &params );
#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<MyAllocatorT>( &params );
if ( params.startupParams.mat != MEM_ACCESS_TYPE::check )
{
params.startupParams.maxItems = maxItems / params.startupParams.threadCount;
params.testRes = testResVoidAlloc + params.startupParams.threadCount;
runTest<VoidAllocatorForTest<MyAllocatorT>>( &params );
}
}
#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<threadCount;++i )
{
printf( " %zd:\n", i );
printThreadStats( "\t", trMy.threadRes[i] );
}
}
printf( "\n" );
const char* memAccessTypeStr = params.startupParams.mat == MEM_ACCESS_TYPE::none ? "none" : ( params.startupParams.mat == MEM_ACCESS_TYPE::single ? "single" : ( params.startupParams.mat == MEM_ACCESS_TYPE::full ? "full" : "unknown" ) );
printf( "Short test summary for \'%s\' and maxItemSizeExp = %zd, maxItems = %zd, iterCount = %zd, allocated memory access mode: %s:\n", MyAllocatorT::name(), params.startupParams.maxItemSize, maxItems, params.startupParams.iterCount, memAccessTypeStr );
printf( "columns:\n" );
printf( "thread,duration(ms),duration of void(ms),diff(ms),RSS max(pages),rssAfterExitingAllThreads(pages),RSS max for void(pages),rssAfterExitingAllThreads for void(pages),allocatedAfterSetup(app level,bytes),allocatedMax(app level,bytes),(RSS max<<12)/allocatedMax\n" );
for ( size_t threadCount=threadMin; threadCount<=threadMax; ++threadCount )
{
TestRes& trVoid = testResVoidAlloc[threadCount];
TestRes& trMy = testResMyAlloc[threadCount];
printf( "%zd,%zd,%zd,%zd,%zd,%zd,%zd,%zd,%zd,%zd,%f\n", threadCount, trMy.duration, trVoid.duration, trMy.duration - trVoid.duration, trMy.rssMax, trMy.rssAfterExitingAllThreads, trVoid.rssMax, trVoid.rssAfterExitingAllThreads, trMy.allocatedAfterSetupSz, trMy.allocatedMax, (trMy.rssMax << 12) * 1. / trMy.allocatedMax );
}
#endif
/* printf( "Short test summary for USE_RANDOMPOS_RANDOMSIZE (alt computations):\n" );
for ( size_t threadCount=threadMin; threadCount<=threadMax; ++threadCount )
{
TestRes& trVoid = testResVoidAlloc[threadCount];
TestRes& trMy = testResMyAlloc[threadCount];
printf( "%zd,%zd,%zd,%zd,%zd,%zd,%zd,%zd,%zd,%zd,%f\n", threadCount, trMy.cumulativeDuration, trVoid.cumulativeDuration, trMy.cumulativeDuration - trVoid.cumulativeDuration, trMy.rssMax, trMy.rssAfterExitingAllThreads, trVoid.rssMax, trVoid.rssAfterExitingAllThreads, trMy.allocatedAfterSetupSz, trMy.allocatedMax, (trMy.rssMax << 12) * 1. / trMy.allocatedMax );
}*/
return 0;
}

View File

@@ -0,0 +1,450 @@
/* -------------------------------------------------------------------------------
* 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 <organization> 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 <COPYRIGHT HOLDER> 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 <stdint.h>
#define NOMINMAX
#include <memory>
#include <stdio.h>
#include <time.h>
#include <thread>
#include <assert.h>
#include <chrono>
#include <random>
#include <limits.h>
#ifndef __GNUC__
#include <intrin.h>
#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)<<idx);
}
inline void testDistribution()
{
constexpr size_t exp = 16;
constexpr size_t testCnt = 0x100000;
size_t bins[exp+1];
memset( bins, 0, sizeof( bins) );
size_t total = 0;
PRNG rng;
for (size_t i=0;i<testCnt;++i)
{
size_t val = calcSizeWithStatsAdjustment( rng.rng64(), exp );
// assert( val <= (((size_t)1)<<exp) );
assert( val );
if ( val <= 8 )
bins[3] +=1;
else
for ( size_t j=4; j<=exp; ++j )
if ( val <= (((size_t)1)<<j) && val > (((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<uint32_t*>(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<uint32_t*>(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<TestBin*>( allocatorUnderTest.allocate( maxItems * sizeof(TestBin) ) );
//else
// baseBuff = reinterpret_cast<TestBin*>( 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<maxItems/32; ++i )
{
uint32_t randNum = rng.rng32();
for ( size_t j=0; j<32; ++j )
if ( (randNum >> 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<uint8_t*>( 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<iterCount>>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].sz/sizeof(size_t ); ++i )
dummyCtr += ( reinterpret_cast<size_t*>( baseBuff[idx].ptr) )[i];
uint8_t* tail = baseBuff[idx].ptr + i * sizeof(size_t );
for ( i=0; i<baseBuff[idx].sz % sizeof(size_t); ++i )
dummyCtr += tail[i];
}
else
{
if constexpr ( mat == MEM_ACCESS_TYPE::single )
dummyCtr += baseBuff[idx].ptr[baseBuff[idx].sz/2];
else
{
static_assert( mat == MEM_ACCESS_TYPE::check, "" );
checkSegment( baseBuff[idx].ptr, baseBuff[idx].sz, baseBuff[idx].reincarnation );
}
}
}
#ifdef COLLECT_USER_MAX_ALLOCATED
allocatedSz -= baseBuff[idx].sz;
#endif
allocatorUnderTest.deallocate( baseBuff[idx].ptr );
baseBuff[idx].ptr = 0;
}
else
{
size_t sz = calcSizeWithStatsAdjustment( rng.rng64(), maxItemSizeExp );
baseBuff[idx].sz = (uint32_t)sz;
baseBuff[idx].ptr = reinterpret_cast<uint8_t*>( 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<maxItems; ++idx )
if ( baseBuff[idx].ptr )
{
if constexpr ( doMemAccess )
{
if constexpr ( mat == MEM_ACCESS_TYPE::full )
{
size_t i=0;
for ( ; i<baseBuff[idx].sz/sizeof(size_t ); ++i )
dummyCtr += ( reinterpret_cast<size_t*>( baseBuff[idx].ptr) )[i];
uint8_t* tail = baseBuff[idx].ptr + i * sizeof(size_t );
for ( i=0; i<baseBuff[idx].sz % sizeof(size_t); ++i )
dummyCtr += tail[i];
}
else
{
if constexpr ( mat == MEM_ACCESS_TYPE::single )
dummyCtr += baseBuff[idx].ptr[baseBuff[idx].sz/2];
else
{
static_assert( mat == MEM_ACCESS_TYPE::check, "" );
checkSegment( baseBuff[idx].ptr, baseBuff[idx].sz, baseBuff[idx].reincarnation );
}
}
}
allocatorUnderTest.deallocate( baseBuff[idx].ptr );
}
//if constexpr ( !allocatorUnderTest.isFake() )
allocatorUnderTest.deallocate( baseBuff );
//else
// allocatorUnderTest.deallocateSlots( baseBuff );
allocatorUnderTest.deinit();
allocatorUnderTest.getTestRes()->rdtscExit = 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

View File

@@ -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 <organization> 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 <COPYRIGHT HOLDER> 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<uint8_t*>(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

View File

@@ -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 <organization> 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 <COPYRIGHT HOLDER> 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

View File

@@ -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 <organization> 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 <COPYRIGHT HOLDER> 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 <stdint.h>
#include <assert.h>
#ifdef _MSC_VER
#include <Windows.h>
#else
#include <time.h>
#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 <psapi.h>
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 <unistd.h>
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

View File

@@ -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 <organization> 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 <COPYRIGHT HOLDER> 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 <memory>
#include <cstdint>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#if _MSC_VER
#include <intrin.h>
#define ALIGN(n) __declspec(align(n))
#define NOINLINE __declspec(noinline)
#define FORCE_INLINE __forceinline
#elif __GNUC__
#if defined(__APPLE__)
#include <time.h>
//#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 <x86intrin.h>
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

View File

@@ -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 <organization> 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 <COPYRIGHT HOLDER> 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 ActualAllocator>
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<uint8_t*>( 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

View File

@@ -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.

View File

@@ -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.
```

View File

@@ -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 <options> < 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 <math.h>
#include <time.h>
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;i<NPROC;i++) {
Place all addresses x such that
&(Local[i]) <= x < &(Local[i])+
sizeof(struct local_memory) on node i
Place all addresses x such that
&(Local[i].mybodytab) <= x < &(Local[i].mybodytab)+
maxmybody * sizeof(bodyptr) - 1 on node i
Place all addresses x such that
&(Local[i].mycelltab) <= x < &(Local[i].mycelltab)+
maxmycell * sizeof(cellptr) - 1 on node i
Place all addresses x such that
&(Local[i].myleaftab) <= x < &(Local[i].myleaftab)+
maxmyleaf * sizeof(leafptr) - 1 on node i
}
}
barrier(Global->Barstart,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].min[i]) {
Local[ProcessId].min[i]=Pos(p)[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; i<NDIM;i++) {
if (Pos(p)[i]<Local[0].min[i]) Local[0].min[i]=Pos(p)[i] ;
if (Pos(p)[i]>Local[0].max[i]) Local[0].max[i]=Pos(p)[i] ;
}
}
SUBV(Local[0].max,Local[0].max,Local[0].min);
for (i=0; i<NDIM;i++) if (side<Local[0].max[i]) side=Local[0].max[i];
ADDVS(Global->rmin,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");
}

View File

@@ -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

View File

@@ -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]);
}

View File

@@ -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 <assert.h>
//#include <ulocks.h>
#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

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -0,0 +1,12 @@
163840
123
0.025
0.05
1.0
2.0
5.0
0.075
0.25
1

View File

@@ -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;k<NSUB;k++) {
if (Subp(c)[k] != NULL) {
printtree(Subp(c)[k]);
}
}
break;
case LEAF:
l = (leafptr) n;
nseq = l->seqnum;
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);
}

View File

@@ -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 <stdio.h>
/*
* 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

View File

@@ -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 <stdio.h>
#include <errno.h>
#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 <sys/types.h>
#include <sys/times.h>
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);
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -0,0 +1,61 @@
#include <ctype.h>
#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);
}

View File

@@ -0,0 +1,268 @@
#include <string.h>
#include <stdio.h>
#include <math.h> /* for findk */
#if defined(_WIN32)
#include <windows.h>
#endif
#include "pdefs.h"
#ifdef __STDC__
#include <stdlib.h>
#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;
}

View File

@@ -0,0 +1,27 @@
#include <stdio.h>
#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;
}

View File

@@ -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 <stdio.h>.
Ditto for AIX 3.2 and <stdlib.h>. */
#ifndef _NO_PROTO
#define _NO_PROTO
#endif
#include <string.h>
#ifdef HAVE_CONFIG_H
#if defined (emacs) || defined (CONFIG_BROKETS)
/* We use <config.h> 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 <config.h>
#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 <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#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 <stdlib.h>
#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 <string.h>
#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 */

View File

@@ -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 */

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -0,0 +1,22 @@
#include "pdefs.h" /* private include file */
#include "precision.h" /* public include file for forward refs */
#include <string.h>
/*
* 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);
}

View File

@@ -0,0 +1,94 @@
#include "pdefs.h"
#include "precision.h"
#include <string.h>
#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);
}

View File

@@ -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 <string.h>
#include <stdio.h>
#include <math.h>
#ifdef __STDC__
#include <stdlib.h>
#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: <x,t,e> */
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;
}

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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 <stdint.h>
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 */

View File

@@ -0,0 +1,315 @@
#include "pdefs.h"
#include "precision.h"
#ifdef DEBUG
#include <stdio.h>
#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;
}

View File

@@ -0,0 +1,55 @@
#include <stdio.h>
#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);
}

View File

@@ -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 <stdio.h>
#endif
extern void pputfactors(FILE *, FactorList);
#endif

View File

@@ -0,0 +1,61 @@
/*
* High Precision Math Library Supplement for floating point routines
*/
#include <stdio.h>
#include <math.h>
#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;
}

View File

@@ -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 */
}

View File

@@ -0,0 +1,36 @@
#include <string.h>
#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
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -0,0 +1,165 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#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);
}

View File

@@ -0,0 +1,84 @@
#include "pdefs.h"
#include "precision.h"
#include <string.h>
#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);
}

View File

@@ -0,0 +1,25 @@
#include "pdefs.h" /* private include file */
#include "precision.h" /* public include file for forward refs */
#include <string.h>
/*
* 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);
}

View File

@@ -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;
}

View File

@@ -0,0 +1,339 @@
#ifdef DEBUGOPS
#include <stdio.h>
#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 <string.h>
#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

View File

@@ -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);
}

View File

@@ -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 <stdlib.h>
#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

View File

@@ -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
};

View File

@@ -0,0 +1,2 @@
extern unsigned int primesize;
extern unsigned short primes[];

View File

@@ -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);
}

View File

@@ -0,0 +1,92 @@
#include "pdefs.h"
#include "precision.h"
#include <string.h>
#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);
}

View File

@@ -0,0 +1,71 @@
#include <string.h>
#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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -0,0 +1,3 @@
extern unsigned long seivesize;
extern unsigned char seive[];

View File

@@ -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);
}

View File

@@ -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
```

View File

@@ -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

View File

@@ -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<last;w++)
{x=p[w]&c[w];if(~(x|x>>1)&DISJOINT)goto lfalse;}}}{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(p[w]&c[w]&mask[w])goto nextvar;goto lfalse;nextvar:;}}
#endif
*Tc++ = p;
lfalse: ;
}
}
*Tc++ = (pcube) NULL; /* sentinel */
Tc_save[1] = (pcube) Tc; /* save pointer to last */
return Tc_save;
}
/*
scofactor -- compute the cofactor of a cover with respect to a cube,
where the cube is "active" in only a single variable.
This routine has been optimized for speed.
*/
pcube *scofactor(T, c, var)
IN pcube *T, c;
IN int var;
{
pcube *Tc, *Tc_save;
register pcube p, mask = cube.temp[1], *T1;
register int first = cube.first_word[var], last = cube.last_word[var];
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(mask, cube.fullset, c));
Tc++;
/* Setup for the quick distance check */
(void) set_and(mask, cube.var_mask[var], c);
/* Loop for each cube in the list, determine suitability, and save */
for(T1 = T+2; (p = *T1++) != NULL; )
if (p != c) {
register int i = first;
do
if (p[i] & mask[i]) {
*Tc++ = p;
break;
}
while (++i <= last);
}
*Tc++ = (pcube) NULL; /* sentinel */
Tc_save[1] = (pcube) Tc; /* save pointer to last */
return Tc_save;
}
void massive_count(T)
IN pcube *T;
{
int *count = cdata.part_zeros;
pcube *T1;
/* Clear the column counts (count of # zeros in each column) */
{ register int i;
for(i = cube.size - 1; i >= 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 */
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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; /* "" */
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;p<last;p+=R->wsize)
#define foreach_remaining_set(R, last, pfirst, p)\
for(p=pfirst+R->wsize,last=R->data+R->count*R->wsize;p<last;p+=R->wsize)
#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;i<R->count;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();

View File

@@ -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;
}

View File

@@ -0,0 +1,166 @@
#include "espresso.h"
#include <stdio.h>
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);
}
}

View File

@@ -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<last;w++){x=p[w]&r[w];if(x=~(x|x>>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;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(p[w]&r[
w]&mask[w])goto nextvar;if(++dist>1)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<lastw;w++){x=p[w]
&r[w];if(~(x|x>>1)&DISJOINT)goto lfalse;}}}{register int w,var,lastw;register
pcube mask;for(var=cube.num_binary_vars;var<cube.num_vars;var++){mask=cube.
var_mask[var];lastw=cube.last_word[var];for(w=cube.first_word[var];w<=lastw;w++)
if(p[w]&r[w]&mask[w])goto nextvar;goto lfalse;nextvar:;}}continue;lfalse:
#endif
BB->active_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<last;w++){x=p[w]&r[w];if(x=~(x|x>>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;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(p[w]&r[
w]&mask[w])goto nextvar;if(++dist>1)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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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
};

View File

@@ -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");
}
}

View File

@@ -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;
}

View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -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 <stdlib.h>
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;
}

View File

@@ -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,
};

View File

@@ -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);
}

Some files were not shown because too many files have changed in this diff Show More