diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..b17277786fe492b8b5760c444fbfe081b86ca607 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# automake artifacts +/Makefile.in +/aclocal.m4 +/autom4te.cache/ +/codes_base_config.h.in +/compile +/config.guess +/config.sub +/configure +/depcomp +/install-sh +/missing + +# configure artifacts +/config.log +/config.status +/Makefile +/stamp-h1 +/codes_base_config.h +/maint/codes-base.pc +.deps + +# make generated artifacts +.dirstamp +*.o +*.a +/src/modelconfig/configparser.h +/src/modelconfig/configparser.c +/src/modelconfig/configlex.h +/src/modelconfig/configlex.c +/tests/lp-io-test + +# hide backups +*~ + +# generated files from test runs +ross.csv diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 0000000000000000000000000000000000000000..5d5760d30a44ee8f466ba5ba350e06435587a898 --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,38 @@ + + COPYRIGHT + +The following is a notice of limited availability of the code, and disclaimer +which must be included in the prologue of the code and in all source listings +of the code. + +Copyright Notice + + 2013 University of Chicago + +Permission is hereby granted to use, reproduce, prepare derivative works, and +to redistribute to others. This software was authored by: + +Mathematics and Computer Science Division +Argonne National Laboratory, Argonne IL 60439 + +(and) + +Computer Science Department +Rensselaer Polytechnic Institute, Troy NY 12180 + + GOVERNMENT LICENSE + +Portions of this material resulted from work developed under a U.S. +Government Contract and are subject to the following license: the Government +is granted for itself and others acting on its behalf a paid-up, nonexclusive, +irrevocable worldwide license in this computer software to reproduce, prepare +derivative works, and perform publicly and display publicly. + + DISCLAIMER + +This computer code material was prepared, in part, as an account of work +sponsored by an agency of the United States Government. Neither the United +States, nor the University of Chicago, nor any of their employees, makes any +warranty express or implied, or assumes any legal liability or responsibility +for the accuracy, completeness, or usefulness of any information, apparatus, +product, or process disclosed, or represents that its use would not infringe +privately owned rights. diff --git a/Make.rules b/Make.rules new file mode 100644 index 0000000000000000000000000000000000000000..aedcde1eb8847193d5b7f768cfdcbee08503fc19 --- /dev/null +++ b/Make.rules @@ -0,0 +1,40 @@ +# flex & bison deps +# +%.c %.h: %.l + $(AM_V_GEN)$(LEX) --header-file=$(@:.c=.h) -o $(@:.h=.c) $< \ + || ( $(RM) $(basename $@).h $(basename $@).c ; exit 1) + +# +# specific rule for codesparser generation; we want the header to land in +# the codes/ directory because it will be installed for use by other repos +#src/iokernellang/codesparser.c codes/codesparser.h: src/iokernellang/codesparser.y +# mkdir -p codes +# @test "x$(bison_ok)" != "yes" || echo "*** WARNING *** Bison version might be too old" +# $(AM_V_GEN)$(YACC) --defines=codes/codesparser.h -o src/iokernellang/codesparser.c $< \ +# || ( $(RM) $(basename $@).h $(basename $@).c ; exit 1) + + +%.c %.h: %.y + @test "x$(bison_ok)" != "yes" || echo "*** WARNING *** Bison version might be too old" + $(AM_V_GEN)$(YACC) --defines=$(@:.c=.h) -o $(@:.h=.c) $< \ + || ( $(RM) $(basename $@).h $(basename $@).c ; exit 1) + + + +# %.y: %.y.in Makefile +# $(AM_V_GEN)$(SED) -e 's,[@]CODES_PURE_PARSER_DEFINES[@],$(CODES_PURE_PARSER_DEFINES),g' \ +# -e 's,[@]CODES_PUSH_PARSER_DEFINES[@],$(CODES_PUSH_PARSER_DEFINES),g' \ +# < src/common/iokernellang/codesparser.y.in > src/common/iokernellang/codesparser.y + +# +# Output dist version +# +.phony: distversion +distversion: + @echo $(VERSION) + +# +# Easy way to build unit tests without running them +# +.phony: tests +tests: $(check_PROGRAMS) diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..d9309a08c6bc3da55248bca5d56aa15b95f3ac48 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,58 @@ +AUTOMAKE_OPTIONS = foreign +ACLOCAL_AMFLAGS = -I m4 + +bin_PROGRAMS = +bin_SCRIPTS = +noinst_LIBRARIES = +noinst_PROGRAMS = +lib_LIBRARIES = +noinst_HEADERS = +TESTS = +check_PROGRAMS = +EXTRA_PROGRAMS = +CLEANFILES = $(bin_SCRIPTS) +EXTRA_DIST = +BUILT_SOURCES = +src_models_CESOURCES = + +# pkgconfig files +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = maint/codes-base.pc +$(pkgconfig_DATA): config.status + +EXTRA_DIST += prepare.sh COPYRIGHT configure.ac reformat.sh uc-codes.cfg + +AM_CPPFLAGS = -I$(top_srcdir)/src ${ROSS_CFLAGS} + +AM_CFLAGS = + +AM_LDFLAGS = ${ROSS_LDFLAGS} + +AM_CXXFLAGS = $(AM_CFLAGS) + +include Make.rules + +include $(top_srcdir)/scripts/Makefile.subdir +include $(top_srcdir)/src/Makefile.subdir +include $(top_srcdir)/tests/Makefile.subdir +include $(top_srcdir)/doc/Makefile.subdir + +if USE_DARSHAN +AM_CPPFLAGS += ${DARSHAN_CFLAGS} -DUSE_DARSHAN=1 +src_libcodes_base_a_SOURCES += src/workload/methods/codes-darshan-io-wrkld.c +tests_workload_codes_workload_test_LDADD += ${DARSHAN_LIBS} +tests_workload_codes_workload_mpi_replay_LDADD += ${DARSHAN_LIBS} +TESTS += tests/workload/darshan-dump.sh +endif + +if USE_RECORDER +AM_CPPFLAGS += ${RECORDER_CPPFLAGS} +src_libcodes_base_a_SOURCES += src/workload/methods/codes-recorder-io-wrkld.c +endif + +if USE_DUMPI +AM_CPPFLAGS += ${DUMPI_CFLAGS} -DUSE_DUMPI=1 +src_libcodes_base_a_SOURCES += src/workload/methods/codes-dumpi-trace-nw-wrkld.c +tests_workload_codes_workload_test_LDADD += ${DUMPI_LIBS} +tests_workload_codes_workload_mpi_replay_LDADD += ${DUMPI_LIBS} +endif diff --git a/codes/codes-callback.h b/codes/codes-callback.h new file mode 100644 index 0000000000000000000000000000000000000000..9c0ee53577499cb196a3bd68695ffe9537cbe4cf --- /dev/null +++ b/codes/codes-callback.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2015 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * +*/ + +#ifndef CODES_CALLBACK_H +#define CODES_CALLBACK_H + +#include +#include "codes/lp-msg.h" + +/* This header defines the following conventions for callback-based event + * processing (i.e., RPC-like event flow where the callee sends a "return + * event" to the caller) + * + * callers: + * - give the caller event size (for sanity checking) + * - use the msg_header convention (lp-msg.h) + * - specify an integer tag to identify which call the callee return event + * corresponds to, in the case of multiple pending callbacks + * - specify an offset to the return structure, which is defined by the callees + * + * callees: + * - use the resulting set of offsets to write and issue the callback + * + * The recommended calling convention for these types of event flows is: + * void event_func(, + * msg_header const * h, int tag, struct codes_cb_info const * cb); + */ + +struct codes_cb_info { + int event_size; + int header_offset; + int tag_offset; + int cb_ret_offset; +}; + +/* helper struct for callees - wrap up the typical inputs */ +struct codes_cb_params { + struct codes_cb_info info; + msg_header h; + int tag; +}; + +/* function-like sugar for initializing a codes_cb_info */ +#define INIT_CODES_CB_INFO(_cb_info_ptr, _event_type, _header_field, _tag_field, _cb_ret_field) \ + do { \ + (_cb_info_ptr)->event_size = sizeof(_event_type); \ + (_cb_info_ptr)->header_offset = offsetof(_event_type, _header_field); \ + (_cb_info_ptr)->tag_offset = offsetof(_event_type, _tag_field); \ + (_cb_info_ptr)->cb_ret_offset = offsetof(_event_type, _cb_ret_field); \ + } while (0) + +#define CB_HO(_cb_params_ptr) ((_cb_params_ptr)->info.header_offset) +#define CB_TO(_cb_params_ptr) ((_cb_params_ptr)->info.tag_offset) +#define CB_RO(_cb_params_ptr) ((_cb_params_ptr)->info.cb_ret_offset) + +/* Declare return variables at the right byte offsets from a codes_cb_params. + * Additionally, set the header and tag vars */ +#define GET_INIT_CB_PTRS(_cb_params_ptr, _data_ptr, _sender_gid_val, _header_nm, _tag_nm, _rtn_name, _rtn_type) \ + msg_header * _header_nm = \ + (msg_header*)((char*)(_data_ptr) + CB_HO(_cb_params_ptr)); \ + int * _tag_nm = \ + (int*)((char*)(_data_ptr) + CB_TO(_cb_params_ptr));\ + _rtn_type * _rtn_name = \ + (_rtn_type*)((char*)(_data_ptr) + CB_RO(_cb_params_ptr)); \ + msg_set_header((_cb_params_ptr)->h.magic, (_cb_params_ptr)->h.event_type, \ + _sender_gid_val, _header_nm); \ + *_tag_nm = (_cb_params_ptr)->tag + +#define SANITY_CHECK_CB(_cb_info_ptr, _ret_type) \ + do { \ + int _total_size = sizeof(_ret_type) + sizeof(int) + sizeof(msg_header);\ + int _esize = (_cb_info_ptr)->event_size; \ + assert(_esize > 0 && \ + (_cb_info_ptr)->header_offset >= 0 && \ + (_cb_info_ptr)->tag_offset >= 0 && \ + (_cb_info_ptr)->cb_ret_offset >= 0); \ + assert(_esize >= _total_size); \ + assert(_esize >= (_cb_info_ptr)->header_offset + sizeof(msg_header)); \ + assert(_esize >= (_cb_info_ptr)->tag_offset + sizeof(int)); \ + assert(_esize >= (_cb_info_ptr)->cb_ret_offset + sizeof(_ret_type)); \ + } while (0) + +#endif /* end of include guard: CODES_CALLBACK_H */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * + * vim: ft=c ts=8 sts=4 sw=4 expandtab + */ diff --git a/codes/codes-jobmap.h b/codes/codes-jobmap.h new file mode 100644 index 0000000000000000000000000000000000000000..a941f16451b93190d407c93034189acc3b432ba1 --- /dev/null +++ b/codes/codes-jobmap.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2015 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +/* SUMMARY - namespace support for multiple groups of ids (jobs) with respect to a + * flat namespace. Note that this API is meant for static job creation - a more + * sophisticated method would need to be used to modify job mappings at + * runtime. + * + * Example: + * + * job 0 1 2 (<-- jobmap defined "job" IDs) + * rank 0 1 2 0 1 0 1 2 3 (<-- "job local" IDs) + * ID 0 1 2 3 4 5 6 7 8 (<-- jobmap-defined LP relative "global" IDs) + * LP A B C D E F G H I (<-- provided by codes-mapping) + * */ + +#ifndef CODES_JOBMAP_H +#define CODES_JOBMAP_H + +/** type markers and parameter defs for jobmaps **/ + +enum codes_jobmap_type { + /* the "identity" jobmap is a shim for single-job workloads */ + CODES_JOBMAP_IDENTITY, + /* the "list" jobmap allows the explicit specification of mappings from + * jobs to lists of global ids through a text file, wiht one line per job + */ + CODES_JOBMAP_LIST, + /* the "dummy" jobmap is an example implementation for testing, and can be + * seen as the inverse of the identity mapping. + * It simply specifies N jobs, with exactly one rank per job, with a trivial + * mapping */ + CODES_JOBMAP_DUMMY, +}; + +struct codes_jobmap_params_identity { + int num_ranks; +}; + +struct codes_jobmap_params_dummy { + int num_jobs; +}; + +struct codes_jobmap_params_list { + char *alloc_file; +}; + + +/** jobmap interface **/ + +struct codes_jobmap_ctx; +struct codes_jobmap_id { + int job; + int rank; // relative to job +}; + +struct codes_jobmap_ctx * +codes_jobmap_configure(enum codes_jobmap_type t, void const * params); + +void codes_jobmap_destroy(struct codes_jobmap_ctx *c); + +/* main mapping functions - bidirectional mapping is needed: + * - global -> local ID for initialization + * - local -> global ID for communication between local IDs + * + * functions return {-1, -1} and -1, respectively, for invalid id input */ + +struct codes_jobmap_id codes_jobmap_to_local_id( + int id, + struct codes_jobmap_ctx const * c); + +int codes_jobmap_to_global_id( + struct codes_jobmap_id id, + struct codes_jobmap_ctx const * c); + +int codes_jobmap_get_num_jobs(struct codes_jobmap_ctx const * c); + +int codes_jobmap_get_num_ranks(int job_id, struct codes_jobmap_ctx const * c); + +#endif + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/codes/codes-mapping-context.h b/codes/codes-mapping-context.h new file mode 100644 index 0000000000000000000000000000000000000000..942956f1f40b83882e15731482216f42ae1c8abb --- /dev/null +++ b/codes/codes-mapping-context.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2015 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +/* SUMMARY - data structure and utilities to direct LP mappings. As opposed to + * the codes-mapping API, this defines metadata necessary to allow implicit + * mappings based on LP type and configuration specification + * (see modelnet, LSM, etc) + * mctx stands for mapping context */ + +#ifndef CODES_MAPPING_CONTEXT_H +#define CODES_MAPPING_CONTEXT_H + +#include +#include + +/* for convenience - an annotation-ignoring "group_modulo" context, + * matching previous mapping behavior in most interfaces (modelnet and such) */ +extern struct codes_mctx const * const CODES_MCTX_DEFAULT; + +/* types of map contexts */ +enum codes_mctx_type { + // instructs those using the context to map directly to an LP + CODES_MCTX_GLOBAL_DIRECT, + // instructs those using the context to map into the same group/repetition + // and compute the callee offset as the modulus of the caller offset and + // the number of callees in the group, to provide simple wraparound + // behaviour + CODES_MCTX_GROUP_MODULO, + // similar to GROUP_MODULO, but maps to offsets in reverse order + CODES_MCTX_GROUP_MODULO_REVERSE, + // instructs those using the context to map into the same group/repetition + // and directly to a callee offset + CODES_MCTX_GROUP_DIRECT, + // unknown/uninitialized context + CODES_MCTX_UNKNOWN +}; + +/* defines whether to specialize by destination annotation, and if so, which + * one */ +struct codes_mctx_annotation { + // see canonical name mapping api in codes_mapping.h. -1 is used for + // ignoring annotations + int cid; +}; + +/* parameters for each mapping context type */ +struct codes_mctx_global_direct { + tw_lpid lpid; +}; + +struct codes_mctx_group_modulo { + struct codes_mctx_annotation anno; +}; +// NOTE: group_modulo_reverse shares the group_modulo representation + +struct codes_mctx_group_direct { + struct codes_mctx_annotation anno; + int offset; +}; + +struct codes_mctx { + enum codes_mctx_type type; + union { + struct codes_mctx_global_direct global_direct; + struct codes_mctx_group_modulo group_modulo; + struct codes_mctx_group_direct group_direct; + } u; +}; + +/* simple setter functions */ +struct codes_mctx codes_mctx_set_global_direct(tw_lpid lpid); + +struct codes_mctx codes_mctx_set_group_modulo( + char const * annotation, + bool ignore_annotations); + +struct codes_mctx codes_mctx_set_group_modulo_reverse( + char const * annotation, + bool ignore_annotations); + +struct codes_mctx codes_mctx_set_group_direct( + int offset, + char const * annotation, + bool ignore_annotations); + +/* helper function to do a codes mapping - this function is subject to change + * based on what types of ctx exist + * NOTE: in GLOBAL_DIRECT mode, dest_lp_name and sender_gid are ignored */ +tw_lpid codes_mctx_to_lpid( + struct codes_mctx const * ctx, + char const * dest_lp_name, + tw_lpid sender_gid); + +/* helper function to extract which annotation a various map context maps to. + * annotation is allocated or NULL if unused */ +char const * codes_mctx_get_annotation( + struct codes_mctx const *ctx, + char const * dest_lp_name, + tw_lpid sender_id); + +#endif /* end of include guard: CODES_MAPPING_CONTEXT_H */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/codes/codes-workload.h b/codes/codes-workload.h new file mode 100644 index 0000000000000000000000000000000000000000..f27d9d907e01dcbefbca9fced973b81b70ab59e0 --- /dev/null +++ b/codes/codes-workload.h @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +/* I/O workload generator API to be used for reading I/O operations into + * storage system simulations. This API just describes the operations to be + * executed; it does not service the operations. + */ + +#ifndef CODES_WORKLOAD_H +#define CODES_WORKLOAD_H + +#include +#include "configuration.h" + +#define MAX_NAME_LENGTH_WKLD 512 + +/* implementations included with codes */ +typedef struct iomock_params iomock_params; +typedef struct iolang_params iolang_params; +typedef struct darshan_params darshan_params; +typedef struct recorder_params recorder_params; + +/* struct to hold the actual data from a single MPI event*/ +typedef struct dumpi_trace_params dumpi_trace_params; +typedef struct checkpoint_wrkld_params checkpoint_wrkld_params; + +struct iomock_params +{ + uint64_t file_id; + int use_uniq_file_ids; + int is_write; + int num_requests; + int request_size; + // for optimizing lookup - set higher (>= num ranks) to reduce collisions + // and 0 to use the default + int rank_table_size; +}; + +struct iolang_params +{ + /* the rank count is defined in the workload config file */ + int num_cns; + /* flag - use path to find kernel files relative to the metafile */ + int use_relpath; + char io_kernel_meta_path[MAX_NAME_LENGTH_WKLD]; + /* set by config in the metadata path */ + char io_kernel_path[MAX_NAME_LENGTH_WKLD]; +}; + +struct darshan_params +{ + char log_file_path[MAX_NAME_LENGTH_WKLD]; + int64_t aggregator_cnt; +}; + +struct recorder_params +{ + char trace_dir_path[MAX_NAME_LENGTH_WKLD]; + int64_t nprocs; +}; + +struct dumpi_trace_params { + char file_name[MAX_NAME_LENGTH_WKLD]; + int num_net_traces; +}; + +struct checkpoint_wrkld_params +{ + int nprocs; /* number of workload processes */ + double checkpoint_sz; /* size of checkpoint, in TiB */ + double checkpoint_wr_bw; /* checkpoint write b/w, in GiB/s */ + int total_checkpoints; /* total number of checkpoint phases */ + double mtti; /* mean time to interrupt, in hours */ +}; + +/* supported I/O operations */ +enum codes_workload_op_type +{ + /* terminator; there are no more operations for this rank */ + CODES_WK_END = 1, + /* sleep/delay to simulate computation or other activity */ + CODES_WK_DELAY, + /* block until specified ranks have reached the same point */ + CODES_WK_BARRIER, + + /* IO operations */ + /* open */ + CODES_WK_OPEN, + /* close */ + CODES_WK_CLOSE, + /* write */ + CODES_WK_WRITE, + /* read */ + CODES_WK_READ, + + /* network operations (modelled after MPI operations) */ + /* blocking send operation */ + CODES_WK_SEND, + /* blocking recv operation */ + CODES_WK_RECV, + /* non-blocking send operation */ + CODES_WK_ISEND, + /* non-blocking receive operation */ + CODES_WK_IRECV, + /* broadcast operation */ + CODES_WK_BCAST, + /* Allgather operation */ + CODES_WK_ALLGATHER, + /* Allgatherv operation */ + CODES_WK_ALLGATHERV, + /* Alltoall operation */ + CODES_WK_ALLTOALL, + /* Alltoallv operation */ + CODES_WK_ALLTOALLV, + /* Reduce operation */ + CODES_WK_REDUCE, + /* Allreduce operation */ + CODES_WK_ALLREDUCE, + /* Generic collective operation */ + CODES_WK_COL, + /* Waitall operation */ + CODES_WK_WAITALL, + /* Wait operation */ + CODES_WK_WAIT, + /* Waitsome operation */ + CODES_WK_WAITSOME, + /* Waitany operation */ + CODES_WK_WAITANY, + /* Testall operation */ + CODES_WK_TESTALL, + /* MPI request free operation*/ + CODES_WK_REQ_FREE, + + /* for workloads that have events not yet handled + * (eg the workload language) */ + CODES_WK_IGNORE +}; + +/* I/O operation paramaters */ +struct codes_workload_op +{ + /* TODO: do we need different "classes" of operations to differentiate + * between different APIs? + */ + + /* what type of operation this is */ + enum codes_workload_op_type op_type; + /* currently only used by network workloads */ + double start_time; + double end_time; + double sim_start_time; + + /* parameters for each operation type */ + union + { + struct { + double seconds; + double nsecs; + } delay; + struct { + int count; /* num ranks in barrier, -1 means "all" */ + int root; /* root rank */ + } barrier; + struct { + uint64_t file_id; /* integer identifier for the file */ + int create_flag; /* file must be created, not just opened */ + } open; + struct { + uint64_t file_id; /* file to operate on */ + off_t offset; /* offset and size */ + size_t size; + } write; + struct { + uint64_t file_id; /* file to operate on */ + off_t offset; /* offset and size */ + size_t size; + } read; + struct { + uint64_t file_id; /* file to operate on */ + } close; + struct { + /* TODO: not sure why source rank is here */ + int source_rank;/* source rank of MPI send message */ + int dest_rank; /* dest rank of MPI send message */ + int num_bytes; /* number of bytes to be transferred over the network */ + int16_t data_type; /* MPI data type to be matched with the recv */ + int count; /* number of elements to be received */ + int tag; /* tag of the message */ + int32_t req_id; + } send; + struct { + /* TODO: not sure why source rank is here */ + int source_rank;/* source rank of MPI recv message */ + int dest_rank;/* dest rank of MPI recv message */ + int num_bytes; /* number of bytes to be transferred over the network */ + int16_t data_type; /* MPI data type to be matched with the send */ + int count; /* number of elements to be sent */ + int tag; /* tag of the message */ + int32_t req_id; + } recv; + /* TODO: non-stub for other collectives */ + struct { + int num_bytes; + } collective; + struct { + int count; + int32_t* req_ids; + } waits; + struct { + int32_t req_id; + } wait; + struct + { + int32_t req_id; + } + free; + }u; +}; + +// helper macro for implementations - call this if multi-app support not +// available +#define APP_ID_UNSUPPORTED(id, name) \ + if (id != 0) \ + tw_error(TW_LOC,\ + "APP IDs not supported for %s generator, 0 required", name); + +/* read workload configuration from a CODES configuration file and return the + * workload name and parameters, which can then be passed to + * codes_workload_load */ +typedef struct +{ + char const * type; + void * params; +} codes_workload_config_return; + +// NOTE: some workloads (iolang, checkpoint) require information about the +// total number of ranks to correctly process traces/config files, etc. Other +// workload generators (darshan) ignore it +codes_workload_config_return codes_workload_read_config( + ConfigHandle * handle, + char const * section_name, + char const * annotation, + int num_ranks); + +void codes_workload_free_config_return(codes_workload_config_return *c); + +/* load and initialize workload of of type "type" with parameters specified by + * "params". The rank is the caller's relative rank within the collection + * of processes that will participate in this workload. The app_id is the + * "application" that the rank is participating in, used to differentiate + * between multiple, concurrent workloads + * + * This function is intended to be called by a compute node LP in a model + * and may be called multiple times over the course of a + * simulation in order to execute different application workloads. + * + * Returns and identifier that can be used to retrieve operations later. + * Returns -1 on failure. + */ +int codes_workload_load( + const char* type, + const char* params, + int app_id, + int rank); + +/* Retrieves the next I/O operation to execute. the wkld_id is the + * identifier returned by the init() function. The op argument is a pointer + * to a structure to be filled in with I/O operation information. + */ +void codes_workload_get_next( + int wkld_id, + int app_id, + int rank, + struct codes_workload_op *op); + +/* Reverse of the above function. */ +void codes_workload_get_next_rc( + int wkld_id, + int app_id, + int rank, + const struct codes_workload_op *op); + +/* Another version of reverse handler. */ +void codes_workload_get_next_rc2( + int wkld_id, + int app_id, + int rank); + +/* Retrieve the number of ranks contained in a workload */ +int codes_workload_get_rank_cnt( + const char* type, + const char* params, + int app_id); + +/* for debugging/logging: print an individual operation to the specified file */ +void codes_workload_print_op( + FILE *f, + struct codes_workload_op *op, + int app_id, + int rank); + +/* implementation structure */ +struct codes_workload_method +{ + char *method_name; /* name of the generator */ + void * (*codes_workload_read_config) ( + ConfigHandle *handle, char const * section_name, + char const * annotation, int num_ranks); + int (*codes_workload_load)(const char* params, int app_id, int rank); + void (*codes_workload_get_next)(int app_id, int rank, struct codes_workload_op *op); + void (*codes_workload_get_next_rc2)(int app_id, int rank); + int (*codes_workload_get_rank_cnt)(const char* params, int app_id); +}; + + +/* dynamically add to the workload implementation table. Must be done BEFORE + * calls to codes_workload_read_config or codes_workload_load */ +void codes_workload_add_method(struct codes_workload_method const * method); + +/* NOTE: there is deliberately no finalize function; we don't have any + * reliable way to tell when a workload is truly done and will not + * participate in further reverse computation. The underlying generators + * will shut down automatically once they have issued their last event. + */ + +#endif /* CODES_WORKLOAD_H */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * + * vim: ft=c ts=8 sts=4 sw=4 expandtab + */ diff --git a/codes/codes.h b/codes/codes.h new file mode 100644 index 0000000000000000000000000000000000000000..d0852a29af1232dadbafac3281ef3a22ba1bcbf6 --- /dev/null +++ b/codes/codes.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + + +#ifndef CODES_H +#define CODES_H + +#include +#include + +// simple deprecation attribute hacking +#if !defined(DEPRECATED) +# if defined(__GNUC__) || defined(__GNUG__) || defined(__clang__) +# define DEPRECATED __attribute__((deprecated)) +# else +# define DEPRECATED +# endif +#endif + +DEPRECATED +static inline tw_event * codes_event_new( + tw_lpid dest_gid, + tw_stime offset_ts, + tw_lp * sender) +{ + tw_stime abs_ts = offset_ts + tw_now(sender); + assert(abs_ts < g_tw_ts_end); + //printf("codes_event_new() abs_ts: %.9f\n", abs_ts); + return(tw_event_new(dest_gid, offset_ts, sender)); +} + +static inline tw_event * tw_event_new_bounded( + tw_lpid dest_gid, + tw_stime offset_ts, + tw_lp * sender) +{ + tw_stime ts = offset_ts + tw_now(sender); + if (ts >= g_tw_ts_end) { + tw_error(TW_LOC, + "LP %lu tried to schedule a message for time %0.5e, " + "%0.5e past the end time\n", + sender->gid, ts, g_tw_ts_end-ts); + return NULL; + } + else + return tw_event_new(dest_gid, offset_ts, sender); +} + + +/* TODO: validate what value we should use here */ +/* Modeled latency for communication between local software components and + * communication between daemons and hardware devices. Measured in + * nanoseconds. + */ +#define CODES_MIN_LATENCY 0.5 +#define CODES_MAX_LATENCY 1.0 +#define CODES_LATENCY_RANGE \ + (CODES_MAX_LATENCY-CODES_MIN_LATENCY) +static inline tw_stime codes_local_latency(tw_lp *lp) +{ + int r = g_tw_nRNG_per_lp-1; + tw_stime tmp; + + tmp = g_tw_lookahead + CODES_MIN_LATENCY + + tw_rand_unif(&lp->rng[r]) * CODES_LATENCY_RANGE; + + if (g_tw_synchronization_protocol == CONSERVATIVE && + (tw_now(lp) + g_tw_lookahead) >= (tw_now(lp) + tmp)) + tw_error(TW_LOC, + "codes_local_latency produced a precision loss " + "sufficient to fail lookahead check (conservative mode) - " + "increase CODES_MIN_LATENCY/CODES_MAX_LATENCY. " + "Now:%0.5le, lookahead:%0.5le, return:%0.5le\n", + tw_now(lp), g_tw_lookahead, tmp); + + return(tmp); +} + +static inline void codes_local_latency_reverse(tw_lp *lp) +{ + int r = g_tw_nRNG_per_lp-1; + tw_rand_reverse_unif(&lp->rng[r]); + return; +} + +#endif /* CODES_H */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ft=c ts=8 sts=4 sw=4 expandtab + */ diff --git a/codes/codes_mapping.h b/codes/codes_mapping.h new file mode 100644 index 0000000000000000000000000000000000000000..5084b78b6310e936e7538f20842686a9b32d6a12 --- /dev/null +++ b/codes/codes_mapping.h @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +/* SUMMARY: + * CODES custom mapping file for ROSS + */ +#include "configuration.h" +#include "codes.h" +#include "lp-type-lookup.h" +#define MAX_NAME_LENGTH 256 + +/* Returns number of LPs on the current PE */ +int codes_mapping_get_lps_for_pe(void); + +/* Takes the global LP ID and returns the rank (PE id) on which the LP is mapped.*/ +tw_peid codes_mapping( tw_lpid gid); + +/* loads the configuration file and sets up the number of LPs on each PE. */ +void codes_mapping_setup(void); + +/* set up lps with an RNG offset + * + * NOTE: manual seeding is discouraged by the ROSS folks, who instead suggest to + * set the number of RNGs each LP will "skip". offset here is a multiplier by + * the global number of LPs + */ +void codes_mapping_setup_with_seed_offset(int offset); + +/*Takes the group name and returns the number of repetitions in the group */ +int codes_mapping_get_group_reps(const char* group_name); + +/* Calculates the count for LPs of the given type + * + * group_name - name of group. If NULL, count is across all groups. + * ignore_repetitions - if group_name is given, then don't include repetitions + * in count. This exists at the moment to support some + * uses of the function that haven't been fleshed out in + * other parts of the API (used by the dragonfly/torus + * models) + * lp_type_name - name of LP type + * annotation - optional annotation. If NULL, entry is considered + * unannotated + * ignore_annos - If zero, then count in an annotation-specific manner. + * If 1, then count the "first-found" LP in the + * configuration, regardless of annotation. + * Otherwise, count across all annotations. + * + * returns the number of LPs found (0 in the case of some combination of group, + * lp_type_name, and annotation not being found) + */ +int codes_mapping_get_lp_count( + const char * group_name, + int ignore_repetitions, + const char * lp_type_name, + const char * annotation, + int ignore_annos); + +/* Calculates the global LP ID given config identifying info. + * + * group_name - name of group + * lp_type_name - name of LP type + * annotation - optional annotation (NULL -> unannotated) + * ignore_anno - ignores annotation and sets gid to the first found LP type + * with matching names + * rep_id - repetition within the group + * offset - lp offset within the repetition + * gid - output ID + * + * If the LP is unable to be found, a tw_error will occur + */ +void codes_mapping_get_lp_id( + const char * group_name, + const char * lp_type_name, + const char * annotation, + int ignore_anno, + int rep_id, + int offset, + tw_lpid * gid); + +/* Calculates the LP ID relative to other LPs (0..N-1, where N is the number of + * LPs sharing the same type) + * + * gid - LP ID + * group_wise - whether to compute id relative to the LP's group + * annotation_wise - whether to compute id relative to the annotation the LP has + */ +int codes_mapping_get_lp_relative_id( + tw_lpid gid, + int group_wise, + int annotation_wise); + +/* Calculates the ROSS global LP ID of an LP given the relative ID and LP type + * information + * + * relative_id - LP id relative to set of "like" LPs + * group_name - name of LP's group. If non-NULL, ID is considered local + * to that group. If NULL, then ID is considered across all + * groups + * lp_type_name - name of the LP to look up. Must be provided + * annotation - LP's annotation. If NULL, ID is considered among + * unannotated LPs + * annotation_wise - whether to consider ID across a specific annotation (using + * the annotation parameter) or all annotations (ignoring the + * annotation parameter) + */ +tw_lpid codes_mapping_get_lpid_from_relative( + int relative_id, + const char * group_name, + const char * lp_type_name, + const char * annotation, + int annotation_wise); + + +/* Returns configuration group information for a given LP-id + * + * gid - LP to look up + * group_name - output LP group name + * group_index - index in config struct of group (mostly used internally) + * lp_type_name - output LP type name + * lp_type_index - index in config struct of lp type (mostly used internally) + * annotation - output annotation (given that the caller is responsible for + * providing the memory, if there's no annotation then the empty + * string is returned) + * rep_id - output repetition within the group + * offset - output LP offset within the LP (for multiple lps in a rep.) + * + * The *_name and annotation parameters can be NULL, in which case the result + * strings aren't copied to them. This is useful when you just need the + * repetition ID and/or the offset. Otherwise, the caller is expected to pass in + * properly-allocated buffers for each (of size MAX_NAME_LENGTH) + */ +void codes_mapping_get_lp_info( + tw_lpid gid, + char * group_name, + int * group_index, + char * lp_type_name, + int * lp_type_index, + char * annotation, + int * rep_id, + int * offset); + +/* same end result as codes_mapping_get_lp_info, except: + * - uses pointer-to-const instead of copying to output parameters. + * much less copying + * - gets rid of arguments that are largely intended for internal usage + * - disambiguates annotation representation - empty string no longer copied + * into annotation argument to indicate no annotation - instead, annotation + * is set to NULL + * + * This function is preferred for performance and simplicity reasons + */ +void codes_mapping_get_lp_info2( + tw_lpid gid, + char const * * group_name, + char const * * lp_type_name, + char const * * annotation, + int * rep_id, + int * offset); + +//void codes_mapping_get_lp_info(tw_lpid gid, char* group_name, int* grp_id, int* lp_type_id, char* lp_type_name, int* grp_rep_id, int* offset); + +/* Returns the annotation for the given LP. + * + * group_name - group name of LP + * lp_type_name - name of the LP + * + * NOTE: This function returns the annotation for the first found LP with + * lp_type_name within the group. In the case of having multiple LP types with + * different annotations in the same group, use the _by_lpid version. + * + * Either the annotation string or NULL (in the case of an unannotated entry) is + * returned. */ +const char* codes_mapping_get_annotation_by_name( + const char * group_name, + const char * lp_type_name); + +/* Returns the annotation for the given LP. + * + * gid - LP id to look up + * + * NOTE: both functions have equivalent results if there is only one LP type in + * the requested group. The different ways of accessing are for convenience. + * This function is the one to use if there are multiple group entries of the + * same LP type (and different annotations) + * + * Either the annotation string or NULL (in the case of an unannotated entry) is + * returned. */ +const char* codes_mapping_get_annotation_by_lpid(tw_lpid gid); + +/* + * Returns a mapping of LP name to all annotations used with the type + * + * lp_name - lp name as used in the configuration + */ +const config_anno_map_t * +codes_mapping_get_lp_anno_map(const char *lp_name); + +/* the following functions are meant to aide in transferring LP mapping + * information across PEs - basically, a canonical mapping of names (group, + * LP, annotations) to indexes. This is separate from the indices returned from + * codes_mapping_get_lp_info, which points directly to configuration entities + */ + +/* returns a canonical index (cid) for the group name, or -1 if not found */ +int codes_mapping_get_group_cid_by_name(char const * group_name); +int codes_mapping_get_group_cid_by_lpid(tw_lpid id); +char const * codes_mapping_get_group_name_by_cid(int cid); + +/* returns a canonical index (cid) for the LP name, or -1 if not found */ +int codes_mapping_get_lp_cid_by_name(char const * lp_type_name); +int codes_mapping_get_lp_cid_by_lpid(tw_lpid id); +char const * codes_mapping_get_lp_name_by_cid(int cid); + +/* returns a canonical index (cid) for an annotation, or -1 if not found. + * NOTE: a NULL or "\0" annotation corresponds to the lack of an annotation */ +int codes_mapping_get_anno_cid_by_name(char const * annotation); +int codes_mapping_get_anno_cid_by_lpid(tw_lpid id); +char const * codes_mapping_get_anno_name_by_cid(int cid); + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/codes/configuration.h b/codes/configuration.h new file mode 100644 index 0000000000000000000000000000000000000000..73b46b8908e18be970693c64bebeb20380873e00 --- /dev/null +++ b/codes/configuration.h @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#ifndef __CONFIGURATION_H__ +#define __CONFIGURATION_H__ + +#include +#include +#include + +#define CONFIGURATION_MAX_NAME 128 +#define CONFIGURATION_MAX_GROUPS 10 +#define CONFIGURATION_MAX_TYPES 10 +#define CONFIGURATION_MAX_ANNOS 10 + +// NOTE: direct offsets are used when first building the structure as we're +// building up one big buffer to hold entity names. Pointers are set after the +// initialization process during configuration_load +typedef union { + char const * ptr; + int offset; +} config_name_u; + +typedef struct config_lptype_s +{ + config_name_u name; + config_name_u anno; + int count; +} config_lptype_t; + +typedef struct config_lpgroup_s +{ + config_name_u name; + int repetitions; + int lptypes_count; + config_lptype_t lptypes[CONFIGURATION_MAX_TYPES]; +} config_lpgroup_t; + +// mapping of lp type to the list of annotations used. Used for convenience when +// models are performing configuraiton code +typedef struct config_anno_map_s +{ + config_name_u lp_name; + // only explicit annotations tracked here - use a flag to indicate a + // non-annotated LP type + int has_unanno_lp; + // for configuration/mapping functions to be able to provide "default" + // (annotation-ignoring) lookup semantics, provide a flag to determine if + // the unannotated lp type is first + int is_unanno_first; + int num_annos; + // maintain the number of lps that have the particular annotation + int num_anno_lps[CONFIGURATION_MAX_ANNOS]; + config_name_u annotations[CONFIGURATION_MAX_ANNOS]; +} config_anno_map_t; + +typedef struct config_lpgroups_s +{ + // counts for the underlying structures, not the number of string entities + int lpgroups_count; + int lpannos_count; + config_lpgroup_t lpgroups[CONFIGURATION_MAX_GROUPS]; + config_anno_map_t lpannos[CONFIGURATION_MAX_TYPES]; + int num_uniq_lptypes; + int num_uniq_annos; + // ptrs into the name buffers + char const ** group_names; + char const ** lp_names; + char const ** anno_names; + char * group_names_buf; + char * lp_names_buf; + char * anno_names_buf; +} config_lpgroups_t; + +typedef struct ConfigVTable * ConfigHandle; + +/* + * Load a configuration on the system (collectively) + * + * filepath - path and name of file + * comm - communicator to distribute file on + * handle - output of configuration + * + * return 0 on success + */ +int configuration_load (const char * filepath, + MPI_Comm comm, + ConfigHandle *handle); + +/* + * Free any resources allocated on load. + * + * handle - configuration handle + */ +int configuration_free (ConfigHandle *handle); + +/* + * Get's the value for a give section/key pair. + * Caller's responsible for transforming it to a useable type. + * Assumes the key name is a KEY configuration type. + * + * handle - configuration handle + * section_name - name of the section the key is in + * key_name - name of the key + * annotation - optional annotation to look for (NULL -> no annotation) + * value - pointer to string + * length - maximum length of string + */ +int configuration_get_value(ConfigHandle *handle, + const char * section_name, + const char * key_name, + const char * annotation, + char *value, + size_t length); + +/* + * Gets the value for a given section/key pair, and interprets it as a path + * relative to the location of the configuration file. + * Assumes the key name is a KEY configuration type. + * Assumes unix path conventions. + * + * handle - configuration handle + * section_name - name of the section the key is in + * key_name - name of the key + * annotation - optional annotation to look for (NULL -> no annotation) + * value - pointer to string + * length - maximum length of string */ +int configuration_get_value_relpath( + ConfigHandle *handle, + const char * section_name, + const char * key_name, + const char * annotation, + char *value, + size_t length); + + +/* + * Get's the values for a give section/key pair which has multiple values. + * Caller's responsible for transforming it to a useable type. + * Assumes the key name is a MULTIKEY configuration type. + * + * handle - configuration handle + * section_name - name of the section the key is in + * key_name - name of the key + * annotation - optional annotation to look for (NULL -> no annotation) + * values - array of points to values (must be freed by caller) + * length - number of value items + */ +int configuration_get_multivalue(ConfigHandle *handle, + const char * section_name, + const char * key_name, + const char * annotation, + char ***values, + size_t *length); + +/* + * Get's the value for a give section/key pair and converts it to an int. + * Assumes the key name is a KEY configuration type. + * + * handle - configuration handle + * section_name - name of the section the key is in + * key_name - name of the key + * annotation - optional annotation to look for (NULL -> no annotation) + * value - returned as a pointer to an integer + */ +int configuration_get_value_int (ConfigHandle *handle, + const char *section_name, + const char *key_name, + const char * annotation, + int *value); + +/* + * Get's the value for a give section/key pair and converts it to an + * unsigned int. + * Assumes the key name is a KEY configuration type. + * + * handle - configuration handle + * section_name - name of the section the key is in + * key_name - name of the key + * annotation - optional annotation to look for (NULL -> no annotation) + * value - returned as a pointer to an unsigned integer + */ +int configuration_get_value_uint (ConfigHandle *handle, + const char *section_name, + const char *key_name, + const char * annotation, + unsigned int *value); + +/* + * Get's the value for a give section/key pair and converts it to a long int. + * Assumes the key name is a KEY configuration type. + * + * handle - configuration handle + * section_name - name of the section the key is in + * key_name - name of the key + * annotation - optional annotation to look for (NULL -> no annotation) + * value - returned as a pointer to a long integer + */ +int configuration_get_value_longint (ConfigHandle *handle, + const char *section_name, + const char *key_name, + const char * annotation, + long int *value); + +/* + * Get's the value for a give section/key pair and converts it to a double. + * Assumes the key name is a KEY configuration type. + * + * handle - configuration handle + * section_name - name of the section the key is in + * key_name - name of the key + * annotation - optional annotation to look for (NULL -> no annotation) + * value - returned as a pointer to a double + */ +int configuration_get_value_double (ConfigHandle *handle, + const char *section_name, + const char *key_name, + const char * annotation, + double *value); + +/* + * Get the LPGROUPS configuration from the config file which is stored + * in the associated data structures. + * + * handle - configuration handle + * section_name - name of section which has the lptypes + * lpgroups - data structure to hold the lpgroup info + */ +int configuration_get_lpgroups (ConfigHandle *handle, + const char *section_name, + config_lpgroups_t *lpgroups); + +/* + * Helper function - get the position in the LP annotation list of the + * given annotation. Used for configuration schemes where an array of + * configuration values is generated based on the annotations in + * config_anno_map_t + * If annotation is not found, -1 is returned */ +int configuration_get_annotation_index(const char * anno, + const config_anno_map_t * anno_map); + +/* + * Forward reference to the configuration handle + */ +extern ConfigHandle config; + +extern config_lpgroups_t lpconf; + +#endif + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/codes/jenkins-hash.h b/codes/jenkins-hash.h new file mode 100644 index 0000000000000000000000000000000000000000..79441db8cec909a49c940857041540f4481a2920 --- /dev/null +++ b/codes/jenkins-hash.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#ifndef __JENKINS_HASH__ +#define __JENKINS_HASH__ + +#include +#include + +/* This header declares and exports Bob Jenkins hash functions define in lookup3.c. + * lookup3.c was downloaded from: http://www.burtleburtle.net/bob/c/lookup3.c + * See: http://www.burtleburtle.net/bob/hash/doobs.html for more information. + * + * Export other functions in that library as necessary. + */ + +void bj_hashlittle2( + const void *key, /* the key to hash */ + size_t length, /* length of the key */ + uint32_t *pc, /* IN: primary initval, OUT: primary hash */ + uint32_t *pb); /* IN: secondary initval, OUT: secondary hash */ + +/* bj_hashsize(shift) gives a hash table size that is a power of 2, good for bj_hashlittle2. + * shift values are: + * + * 1024 -> 10 + * 4096 -> 12 + * 16384 -> 14 + * 65536 -> 16 + * 262144 -> 18 + * 1048576 -> 20 + */ +#define bj_hashsize(n) ((uint32_t)1<<(n)) + +/* bj_hashmask(n) gives a mask reasonable for returning a hash between 0 and the hashtable size. + */ +#define bj_hashmask(n) (bj_hashsize(n)-1) + +#endif + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/codes/local-storage-model.h b/codes/local-storage-model.h new file mode 100644 index 0000000000000000000000000000000000000000..7714d60cdd942de29fb80979528e4cbefa43bca2 --- /dev/null +++ b/codes/local-storage-model.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#ifndef __LS_MODEL__ +#define __LS_MODEL__ + +#include + +#include "codes-callback.h" +#include "codes-mapping-context.h" + +#define LSM_NAME "lsm" + +/* HACK: problems arise when some LP sends multiple messages as part of an + * event and expects FCFS ordering. One could simply set a higher delay in + * delay, but that is hacky as well (and relies on knowing bounds on internal + * codes_local_latency bounds. Hence, expose explicit start-sequence and + * stop-sequence markers */ +extern int lsm_in_sequence; +extern tw_stime lsm_msg_offset; +#define LSM_START_SEQ() do {\ + lsm_in_sequence = 1; \ + lsm_msg_offset = 0.0; \ +} while (0) +#define LSM_END_SEQ() do {\ + lsm_in_sequence = 0;\ +} while (0) + +/* + * lsm_event_t + * - events supported by the local storage model + */ +typedef enum lsm_event_e +{ + LSM_WRITE_REQUEST = 1, + LSM_READ_REQUEST = 2, + LSM_WRITE_COMPLETION = 3, + LSM_READ_COMPLETION = 4 +} lsm_event_t; + +/* + * return type for lsm events (in the codes-callback sense) + */ +typedef struct { + int rc; +} lsm_return_t; + +/* + * Prototypes + */ + +/* given LP sender, find the LSM device LP in the same group */ +tw_lpid lsm_find_local_device( + struct codes_mctx const * map_ctx, + tw_lpid sender_gid); + +/* + * lsm_io_event + * - creates a new event that is targeted for the corresponding + * LSM LP. + * - this event will allow wrapping the callers completion event + * - lp_io_category: string name to identify the traffic category for use in + * lp-io + * - gid_offset: relative offset of the LSM LP to the originating LP + * - io_object: id of byte stream the caller will modify + * - io_offset: offset into byte stream + * - io_size_bytes: size in bytes of IO request + * - io_type: read or write request + */ + +void lsm_io_event( + const char * lp_io_category, + uint64_t io_object, + int64_t io_offset, + uint64_t io_size_bytes, + int io_type, + tw_stime delay, + tw_lp *sender, + struct codes_mctx const * map_ctx, + int return_tag, + msg_header const * return_header, + struct codes_cb_info const * cb); + +void lsm_io_event_rc(tw_lp *sender); + +/* get the priority count for the LSM scheduler. + * returns 0 if priorities aren't being used, -1 if no LSMs were configured, + * and >0 otherwise. + * This should not be called before lsm_configure */ +int lsm_get_num_priorities( + struct codes_mctx const * map_ctx, + tw_lpid sender_id); + +/* set a request priority for the following lsm_event_*. + * - tw_error will be called if the priority ends up being out-of-bounds + * (won't able to tell until the lsm_event call b/c annotations) + * - not setting a priority (or setting a negative priority) is equivalent to + * setting the message to the lowest priority + */ +void lsm_set_event_priority(int prio); + +/* registers the storage model LP with CODES/ROSS */ +void lsm_register(void); + +/* configures the LSM model(s) */ +void lsm_configure(void); + +#define LSM_DEBUG 0 + +#endif + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ft=c ts=8 sts=4 sw=4 expandtab + */ diff --git a/codes/lp-io.h b/codes/lp-io.h new file mode 100644 index 0000000000000000000000000000000000000000..93b46fdfad2566ce559bcb4f47d804c810e662e6 --- /dev/null +++ b/codes/lp-io.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#ifndef LP_IO_H +#define LP_IO_H + +#include + +typedef char* lp_io_handle; + +#define LP_IO_UNIQ_SUFFIX 1 + +/* to be called (collectively) before running simulation to prepare the + * output directory. + */ +int lp_io_prepare(char *directory, int flags, lp_io_handle* handle, MPI_Comm comm); + +/* to be called within LPs to store a block of data */ +int lp_io_write(tw_lpid gid, char* identifier, int size, void* buffer); + +/* undo the immediately preceding write for the given LP */ +int lp_io_write_rev(tw_lpid gid, char* identifier); + +/* to be called (collectively) after tw_run() to flush data to disk */ +int lp_io_flush(lp_io_handle handle, MPI_Comm comm); + +/* retrieves the directory name for a handle */ +static inline char* lp_io_handle_to_dir(lp_io_handle handle) +{ + return(strdup(handle)); +} + +#endif /* LP_IO_H */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ft=c ts=8 sts=4 sw=4 expandtab + */ diff --git a/codes/lp-msg.h b/codes/lp-msg.h new file mode 100644 index 0000000000000000000000000000000000000000..f98841bf99b652bdf0e74af662432cda35326097 --- /dev/null +++ b/codes/lp-msg.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2014 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * +*/ + +#ifndef LP_MSG_H +#define LP_MSG_H + +#include "ross.h" + +/* It is good practice to always include the src LPID, a unique message + * identifier, and a "magic" number to ensure that the LP type receiving the + * message is the intended recipient. This is formalized in the following + * struct and is used in a few places where LP-to-LP communication is + * abstracted */ + +typedef struct msg_header_s { + tw_lpid src; + int event_type; + int magic; +} msg_header; + +/* data structure utilities */ +void msg_set_header(int magic, int event_type, tw_lpid src, msg_header *h); + +#endif /* end of include guard: LP_MSG_H */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/codes/lp-type-lookup.h b/codes/lp-type-lookup.h new file mode 100644 index 0000000000000000000000000000000000000000..18786ca706843f1e94a55ff6da4b20cd83297c19 --- /dev/null +++ b/codes/lp-type-lookup.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + + +#ifndef LP_TYPE_LOOKUP_H +#define LP_TYPE_LOOKUP_H + +#include "ross.h" + +/* look up the lp type registered through lp_type_register. Mostly used + * internally */ +const tw_lptype* lp_type_lookup(const char* name); + +/* register an LP with CODES/ROSS */ +void lp_type_register(const char* name, const tw_lptype* type); + +#endif /* LP_TYPE_LOOKUP_H */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ft=c ts=8 sts=4 sw=4 expandtab + */ diff --git a/codes/quickhash.h b/codes/quickhash.h new file mode 100644 index 0000000000000000000000000000000000000000..b045350724fd4cc36fd85936de256e3f442e4aa0 --- /dev/null +++ b/codes/quickhash.h @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +/* 2001 Clemson University and The University of Chicago + * + * See COPYING in top-level directory. + */ + +/* quickhash.h imported from PVFS2 repo rev 1.19 */ + +#ifndef SRC_COMMON_UTIL_QUICKHASH_H +#define SRC_COMMON_UTIL_QUICKHASH_H + +#include +#include +#include "codes/quicklist.h" + +#define qhash_malloc(x) malloc(x) +#define qhash_free(x) free(x) +#define qhash_head qlist_head +#define INIT_QHASH_HEAD INIT_QLIST_HEAD +#define qhash_entry qlist_entry +#define qhash_add_tail qlist_add_tail +#define qhash_del qlist_del +#define qhash_for_each qlist_for_each +#define qhash_for_each_safe qlist_for_each_safe + +#define qhash_lock_init(lock_ptr) do {} while(0) +#define qhash_lock(lock_ptr) do {} while(0) +#define qhash_unlock(lock_ptr) do {} while(0) + +struct qhash_table +{ + struct qhash_head *array; + int table_size; + int (*compare) (void *key, struct qhash_head * link); + int (*hash) (void *key, int table_size); +}; + +/* qhash_init() + * + * creates a new hash table with the specified table size. The + * hash function and compare function must be provided. + * table_size should be a good prime number. + * + * the compare function tests equality between the input key + * and the given qhash entry, returning 1 on equal and 0 on + * non-equal + * + * returns pointer to table on success, NULL on failure + */ +static inline struct qhash_table *qhash_init( + int (*compare) (void *key, + struct qhash_head * link), + int (*hash) (void *key, + int table_size), + int table_size) +{ + int i = 0; + struct qhash_table *new_table = NULL; + + /* create struct to contain table information */ + new_table = (struct qhash_table *) + qhash_malloc(sizeof(struct qhash_table)); + if (!new_table) + { + return (NULL); + } + + /* fill in info */ + new_table->compare = compare; + new_table->hash = hash; + new_table->table_size = table_size; + + /* create array for actual table */ + new_table->array = (struct qhash_head *) + qhash_malloc(sizeof(struct qhash_head) * table_size); + if (!new_table->array) + { + qhash_free(new_table); + return (NULL); + } + + /* initialize a doubly linked at each hash table index */ + for (i = 0; i < table_size; i++) + { + INIT_QHASH_HEAD(&new_table->array[i]); + } + qhash_lock_init(&new_table->lock); + + return (new_table); +} + + +/* qhash_finalize() + * + * frees any resources created by the hash table + * + * no return value + */ +static inline void qhash_finalize( + struct qhash_table *old_table) +{ + qhash_free(old_table->array); + qhash_free(old_table); + return; +} + +/* qhash_add() + * + * adds a new link onto the hash table, hashes based on given key + * + * no return value + */ +static inline void qhash_add( + struct qhash_table *table, + void *key, + struct qhash_head *link) +{ + int index = 0; + + /* hash on the key */ + index = table->hash(key, table->table_size); + + /* add to the tail of the linked list at that offset */ + qhash_lock(&table->lock); + qhash_add_tail(link, &(table->array[index])); + qhash_unlock(&table->lock); + + return; +} + +/* qhash_search() + * + * searches for a link in the hash table + * that matches the given key + * + * returns pointer to link on success, NULL on failure (or item + * not found) + */ +static inline struct qhash_head *qhash_search( + struct qhash_table *table, + void *key) +{ + int index = 0; + struct qhash_head *tmp_link = NULL; + + /* find the hash value */ + index = table->hash(key, table->table_size); + + /* linear search at index to find match */ + qhash_lock(&table->lock); + qhash_for_each(tmp_link, &(table->array[index])) + { + if (table->compare(key, tmp_link)) + { + qhash_unlock(&table->lock); + return (tmp_link); + } + } + qhash_unlock(&table->lock); + return (NULL); +} + +/* qhash_search_at_index() + * + * searches for a link in the list matching + * the specified index + * + * returns pointer to link on success, NULL on failure (or item + * not found) + */ +static inline struct qhash_head *qhash_search_at_index( + struct qhash_table *table, + int index) +{ + struct qhash_head *tmp_link = NULL; + + if(index >= table->table_size) + { + return NULL; + } + + qhash_lock(&table->lock); + qhash_for_each(tmp_link, &(table->array[index])) + { + qhash_unlock(&table->lock); + return (tmp_link); + } + qhash_unlock(&table->lock); + return (NULL); +} + +/* qhash_search_and_remove() + * + * searches for and removes a link in the hash table + * that matches the given key + * + * returns pointer to link on success, NULL on failure (or item + * not found). On success, link is removed from hashtable. + */ +static inline struct qhash_head *qhash_search_and_remove( + struct qhash_table *table, + void *key) +{ + int index = 0; + struct qhash_head *tmp_link = NULL; + + /* find the hash value */ + index = table->hash(key, table->table_size); + + /* linear search at index to find match */ + qhash_lock(&table->lock); + qhash_for_each(tmp_link, &(table->array[index])) + { + if (table->compare(key, tmp_link)) + { + qhash_del(tmp_link); + qhash_unlock(&table->lock); + return (tmp_link); + } + } + qhash_unlock(&table->lock); + return (NULL); +} + +/* qhash_search_and_remove_at_index() + * + * searches for and removes the first link in the list + * matching the specified index + * + * returns pointer to link on success, NULL on failure (or item + * not found). On success, link is removed from hashtable. + */ +static inline struct qhash_head *qhash_search_and_remove_at_index( + struct qhash_table *table, + int index) +{ + struct qhash_head *tmp_link = NULL; + + if(index >= table->table_size) + { + return NULL; + } + + qhash_lock(&table->lock); + qhash_for_each(tmp_link, &(table->array[index])) + { + qhash_del(tmp_link); + qhash_unlock(&table->lock); + return (tmp_link); + } + qhash_unlock(&table->lock); + return (NULL); +} + +#define qhash_destroy_and_finalize(_oldtable, _entry_type, _link, _destructor) \ + do \ + { \ + int i = 0; \ + struct qhash_head *entry; \ + struct qhash_head *tmpe; \ + qhash_lock(&_oldtable->lock); \ + for(i = 0; i < _oldtable->table_size; ++i) \ + { \ + qhash_for_each_safe(entry, tmpe, &(_oldtable->array[i])) \ + { \ + qhash_del(entry); \ + _destructor(qhash_entry(entry, _entry_type, _link)); \ + } \ + } \ + qhash_unlock(&_oldtable->lock); \ + \ + qhash_finalize(_oldtable); \ + \ + } while(0) + +/* http://www.cris.com/~Ttwang/tech/inthash.htm */ +static inline int quickhash_32bit_hash(void *k, int table_size) +{ + int32_t key = *(int32_t *)k; + key = ~key + (key << 15); /* key = (key << 15) - key - 1; */ + key = key ^ (key >> 12); + key = key + (key << 2); + key = key ^ (key >> 4); + key = key * 2057; /* key = (key + (key << 3)) + (key << 11); */ + key = key ^ (key >> 16); + + return (int) (key & (table_size - 1)); +} + +static inline int quickhash_64bit_hash(void *k, int table_size) +{ + uint64_t key = *(uint64_t *)k; + + key = (~key) + (key << 18); /* key = (key << 18) - key - 1; */ + key = key ^ (key >> 31); + key = key * 21; /* key = (key + (key << 2)) + (key << 4); */ + key = key ^ (key >> 11); + key = key + (key << 6); + key = key ^ (key >> 22); + + return (int) (key & ((uint64_t)(table_size - 1))); +} + +/** + * derived from an algorithm found in Aho, Sethi and Ullman's + * {Compilers: Principles, Techniques and Tools}, published by Addison-Wesley. + * This algorithm comes from P.J. Weinberger's C compiler. + */ +static inline int quickhash_string_hash(void *k, int table_size) +{ + const char *str = (char *)k; + uint32_t g, h = 0; + + while(*str) + { + h = (h << 4) + *str++; + if((g = (h & 0xF0UL))) + { + h ^= g >> 24; + h ^= g; + } + } + + return (int)(h & ((uint64_t)(table_size - 1))); +} + +/* used for cases where we the key is already in good shape for hashing */ +static inline int quickhash_null32_hash(void *k, int table_size) +{ + uint32_t *tmp = (uint32_t*)k; + return(int)(*tmp & (table_size - 1)); +} + +#endif /* SRC_COMMON_UTIL_QUICKHASH_H */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/codes/quicklist.h b/codes/quicklist.h new file mode 100644 index 0000000000000000000000000000000000000000..416b16cfa3842d3ac25593e748b58bbb5f4d2733 --- /dev/null +++ b/codes/quicklist.h @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +/* + * (C) 2001 Clemson University and The University of Chicago + * + * See COPYING in top-level directory. + */ + +/* Derived from linked qlist code taken from linux 2.4.3 (list.h) */ + +/* + * Simple doubly linked qlist implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole qlists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +#ifndef QUICKLIST_H +#define QUICKLIST_H + +#include + +struct qlist_head { + struct qlist_head *next, *prev; +}; + +#define QLIST_HEAD_INIT(name) { &(name), &(name) } + +#define QLIST_HEAD(name) \ + struct qlist_head name = QLIST_HEAD_INIT(name) + +#define INIT_QLIST_HEAD(ptr) do { \ + (ptr)->next = (ptr); (ptr)->prev = (ptr); \ +} while (0) + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal qlist manipulation where we know + * the prev/next entries already! + */ +static __inline__ void __qlist_add(struct qlist_head * newi, + struct qlist_head * prev, + struct qlist_head * next) +{ + next->prev = newi; + newi->next = next; + newi->prev = prev; + prev->next = newi; +} + +/** + * qlist_add - add a new entry + * @new: new entry to be added + * @head: qlist head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static __inline__ void qlist_add(struct qlist_head *newi, struct qlist_head *head) +{ + __qlist_add(newi, head, head->next); +} + +/** + * qlist_add_tail - add a new entry + * @new: new entry to be added + * @head: qlist head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static __inline__ void qlist_add_tail(struct qlist_head *newi, struct qlist_head *head) +{ + __qlist_add(newi, head->prev, head); +} + +/* + * Delete a qlist entry by making the prev/next entries + * point to each other. + * + * This is only for internal qlist manipulation where we know + * the prev/next entries already! + */ +static __inline__ void __qlist_del(struct qlist_head * prev, + struct qlist_head * next) +{ + next->prev = prev; + prev->next = next; +} + +/** + * qlist_del - deletes entry from qlist. + * @entry: the element to delete from the qlist. + * Note: qlist_empty on entry does not return true after this, the entry is in an undefined state. + */ +static __inline__ void qlist_del(struct qlist_head *entry) +{ + __qlist_del(entry->prev, entry->next); +} + +/** + * qlist_del_init - deletes entry from qlist and reinitialize it. + * @entry: the element to delete from the qlist. + */ +static __inline__ void qlist_del_init(struct qlist_head *entry) +{ + __qlist_del(entry->prev, entry->next); + INIT_QLIST_HEAD(entry); +} + +/** + * qlist_empty - tests whether a qlist is empty + * @head: the qlist to test. + */ +static __inline__ int qlist_empty(struct qlist_head *head) +{ + return head->next == head; +} + +/** + * qlist_pop - pop the first item off the list and return it + * @head: qlist to modify + */ +static __inline__ struct qlist_head* qlist_pop(struct qlist_head *head) +{ + struct qlist_head *item = NULL; + + if (!qlist_empty(head)) + { + item = head->next; + qlist_del(item); + } + + return item; +} + +/** + * qlist_pop_back - pop the last item off the list and return it + * @head: qlist to modify + */ +static __inline__ struct qlist_head* qlist_pop_back(struct qlist_head *head) +{ + struct qlist_head *item = NULL; + + if (!qlist_empty(head)) + { + item = head->prev; + qlist_del(item); + } + + return item; +} + +/** + * qlist_splice - join two qlists + * @qlist: the new qlist to add. + * @head: the place to add it in the first qlist. + */ +static __inline__ void qlist_splice(struct qlist_head *qlist, struct qlist_head *head) +{ + struct qlist_head *first = qlist->next; + + if (first != qlist) { + struct qlist_head *last = qlist->prev; + struct qlist_head *at = head->next; + + first->prev = head; + head->next = first; + + last->next = at; + at->prev = last; + } +} + +/** + * qlist_entry - get the struct for this entry + * @ptr: the &struct qlist_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the qlist_struct within the struct. + */ +#define qlist_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)((&((type *)0)->member)))) + +/** + * qlist_for_each - iterate over a qlist + * @pos: the &struct qlist_head to use as a loop counter. + * @head: the head for your qlist. + */ +#define qlist_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_safe - iterate over a list safe against + * removal of list entry + * @pos: the &struct list_head to use as a loop counter. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define qlist_for_each_safe(pos, scratch, head) \ + for (pos = (head)->next, scratch = pos->next; pos != (head);\ + pos = scratch, scratch = pos->next) + +/** + * qlist_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop counter. + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define qlist_for_each_entry(pos, head, member) \ + for (pos = qlist_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = qlist_entry(pos->member.next, typeof(*pos), member)) \ + +/** + * qlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos: the type * to use as a loop counter. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_struct within the struct. + */ +#define qlist_for_each_entry_safe(pos, n, head, member) \ + for (pos = qlist_entry((head)->next, typeof(*pos), member), \ + n = qlist_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = qlist_entry(n->member.next, typeof(*n), member)) + +static inline int qlist_exists(struct qlist_head *list, struct qlist_head *qlink) +{ + struct qlist_head *pos; + + if(qlist_empty(list)) return 0; + + qlist_for_each(pos, list) + { + if(pos == qlink) + { + return 1; + } + } + return 0; +} + +static inline int qlist_count(struct qlist_head *list) +{ + struct qlist_head *pos; + int count = 0; + + pos = list->next; + + while(pos != list) + { + ++count; + pos = pos->next; + } + + return count; +} + +static inline struct qlist_head * qlist_find( + struct qlist_head *list, + int (*compare)(struct qlist_head *, void *), + void *ptr) +{ + struct qlist_head *pos; + qlist_for_each(pos, list) + { + if(compare(pos, ptr)) + { + return pos; + } + } + return NULL; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ + +#endif /* QUICKLIST_H */ diff --git a/codes/rc-stack.h b/codes/rc-stack.h new file mode 100644 index 0000000000000000000000000000000000000000..718e49766e3ba99dd6e9d924f3dae684f9da3fab --- /dev/null +++ b/codes/rc-stack.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2014 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#ifndef RC_STACK_H +#define RC_STACK_H + +#include + +/* A simple stack data structure that is GVT-aware for cleanup purposes. It's + * meant to use as an alternative to event-stuffing for allocating data that + * would be too large to put into the event. + * + * It's currently overly simple and will not perform well for workloads that + * hit the RC stack often. Just currently meant to act as a simple placeholder + * until we have time to do a high-performance implementation. + * + * TODO: + * - use dedicated memory (pass out mem for data, use singly-linked-list of + * large-ish chunks to prevent lots of malloc/free calls) + * - provide better options for invoking garbage collection (enter collection + * loop if more than N entries present, every X events, etc.). Don't want to + * enter the loop every event or modify the list every time gvt changes. + */ + +struct rc_stack; + +void rc_stack_create(struct rc_stack **s); +void rc_stack_destroy(struct rc_stack *s); + +/* push data to the stack with time given by tw_now(lp). + * a NULL free function will do nothing with the data on GC + * (useful for debugging) */ +void rc_stack_push( + tw_lp const *lp, + void *data, + void (*free_fn)(void*), + struct rc_stack *s); + +/* pop data from the stack for rc (tw_error if stack empty) */ +void * rc_stack_pop(struct rc_stack *s); + +/* get the number of entries on the stack (mostly for debug) */ +int rc_stack_count(struct rc_stack const *s); + +/* remove entries from the stack with generation time < GVT (lp->pe->GVT). + * a NULL lp causes a delete-all */ +void rc_stack_gc(tw_lp const *lp, struct rc_stack *s); + +#endif /* end of include guard: RC-STACK_H */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/codes/resource-lp.h b/codes/resource-lp.h new file mode 100644 index 0000000000000000000000000000000000000000..1fad06436ea04e90ed23f974c1e9509bb8dd4606 --- /dev/null +++ b/codes/resource-lp.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2014 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * +*/ + +/* this header defines the user-facing functionality needed to interact with a + * resource LP. All of the LP-specific implementation details are in the + * corresponding C file */ + +#ifndef RESOURCE_LP_H +#define RESOURCE_LP_H + +#include +#include + +#include "lp-msg.h" +#include "resource.h" +#include "codes-callback.h" +#include "codes-mapping-context.h" + +#define RESOURCE_LP_NM "resource" + +typedef struct { + int ret; + /* in the case of a reserve, need to return the token */ + resource_token_t tok; +} resource_return; + + +/* registers the resource LP with CODES/ROSS */ +void resource_lp_init(); + +/* reads the resource LP configuration */ +void resource_lp_configure(); + +/* Wrappers for the underlying resource structure. + * Implicitly maps the given LPID to it's group and repetition, then messages + * the resource LP with the request. + * The following functions expect the sending LP to put its magic and callback + * event type into the header parameter (lpid not necessary, it's grabbed from + * sender) + * + * block_on_unavail - flag whether to wait to message the requester if + * request cannot be satisfied + * return_tag, return_header - set in the return client event, using the offsets in cb + */ +void resource_lp_get( + uint64_t req, + int block_on_unavail, + tw_lp *sender, + struct codes_mctx const * map_ctx, + int return_tag, + msg_header const *return_header, + struct codes_cb_info const *cb); +/* no callback for frees thus far */ +void resource_lp_free( + uint64_t req, + tw_lp *sender, + struct codes_mctx const * map_ctx); +void resource_lp_reserve( + uint64_t req, + int block_on_unavail, + tw_lp *sender, + struct codes_mctx const * map_ctx, + int return_tag, + msg_header const *return_header, + struct codes_cb_info const *cb); +void resource_lp_get_reserved( + uint64_t req, + resource_token_t tok, + int block_on_unavail, + tw_lp *sender, + struct codes_mctx const * map_ctx, + int return_tag, + msg_header const *return_header, + struct codes_cb_info const *cb); +void resource_lp_free_reserved( + uint64_t req, + resource_token_t tok, + tw_lp *sender, + struct codes_mctx const * map_ctx); + +/* rc functions - thankfully, they only use codes-local-latency, so no need + * to pass in any arguments */ +void resource_lp_get_rc(tw_lp *sender); +void resource_lp_free_rc(tw_lp *sender); +void resource_lp_reserve_rc(tw_lp *sender); +void resource_lp_get_reserved_rc(tw_lp *sender); +void resource_lp_free_reserved_rc(tw_lp *sender); + +#endif /* end of include guard: RESOURCE_LP_H */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/codes/resource.h b/codes/resource.h new file mode 100644 index 0000000000000000000000000000000000000000..fe6b7c3e05658a59f1728ae33a77e0413447d280 --- /dev/null +++ b/codes/resource.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2014 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * +*/ + +/* Implementation of a simple "resource" data structure for lps to get and + * retrieve. Additionally allows 'reservations' of a resource for + * later use, allowing claiming of the resource without requiring the LP to + * reimplement resource functionality. General requests go through the + * "general" pool (unreserved part of the resource and + * reservation-specific requests go through their specific pools. */ + +#ifndef RESOURCE_H +#define RESOURCE_H + +#include + + +typedef struct resource_s resource; +typedef unsigned int resource_token_t; + +/* initialize with avail capacity, all unreserved */ +void resource_init(uint64_t avail, resource *r); + +/* Acquire req units of the resource. + * Returns 0 on success, 1 on failure (not enough available), 2 on invalid + * token. */ +int resource_get(uint64_t req, resource_token_t tok, resource *r); + +/* Release req units of the resource. + * Returns 0 on success, 2 on invalid token */ +int resource_free(uint64_t req, resource_token_t tok, resource *r); + +/* Determine amount of resource units remaining + * Returns 0 on success, 2 on invalid token */ +int resource_get_avail(resource_token_t tok, uint64_t *avail, resource *r); + +/* Determine amount of used resource units. + * The number returned is based on the pool-specific maximums, for which + * reserve calls can change */ +int resource_get_used(resource_token_t tok, uint64_t *used, resource *r); + +/* Get and restore minimum stat (support for RC). So that the resource + * interface doesn't need to upgrade to a full LP, store stats in + * caller-provided arguments. */ +int resource_get_min_avail(resource_token_t tok, uint64_t *min_avail, + resource *r); +int resource_restore_min_avail(resource_token_t tok, uint64_t min_avail, + resource *r); + +/* Reservation functions, same return value as get. + * These functions expect exactly one caller per LP group as + * defined by the codes configuration + * TODO: "un-reserving" not yet supported */ +int resource_reserve(uint64_t req, resource_token_t *tok, resource *r); + +#define MAX_RESERVE 8 +struct resource_s { + // index 0 is the general pool, 1... are the reserved pools + // current available + uint64_t avail[MAX_RESERVE+1]; + // maximums per pool (the max for the general pool is reduced on reserve!) + uint64_t max[MAX_RESERVE+1]; + // statistics - minimum available at any time + uint64_t min_avail[MAX_RESERVE+1]; + // global maximum + uint64_t max_all; + unsigned int num_tokens; +}; + + +#endif /* end of include guard: RESOURCE_H */ + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/configure.ac b/configure.ac new file mode 100755 index 0000000000000000000000000000000000000000..0d316eac81b523348f8601263a098cb86e4f34b1 --- /dev/null +++ b/configure.ac @@ -0,0 +1,133 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.67]) +AC_INIT([codes-base], [0.4.0], [http://trac.mcs.anl.gov/projects/codes/newticket],[],[http://www.mcs.anl.gov/projects/codes/]) + +AC_CANONICAL_TARGET +AC_CANONICAL_SYSTEM +AC_CANONICAL_HOST + +AM_INIT_AUTOMAKE([foreign subdir-objects -Wall]) + +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +AC_CONFIG_SRCDIR([doc/BUILD_STEPS]) +AC_CONFIG_HEADERS([codes_base_config.h]) + +AX_PROG_BISON([],[AC_MSG_WARN([Could not find bison])]) +AX_PROG_FLEX([],[AC_MSG_WARN([Could not find flex])]) +AC_SUBST([BISON]) +AC_SUBST([FLEX]) + +# Checks for programs. +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_CXX +AC_PROG_CXXCPP +AC_PROG_RANLIB + +PKG_PROG_PKG_CONFIG + +# Check for C99 +AC_PROG_CC_C99 + +AC_REQUIRE_CPP + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([stdlib.h string.h unistd.h execinfo.h pthread.h malloc.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_TYPE_INT8_T +AC_TYPE_INT16_T +AC_TYPE_INT32_T +AC_TYPE_INT64_T +AC_TYPE_UINT8_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T + +# Checks for library functions. +AC_CHECK_FUNCS([memset]) +AC_CHECK_LIB([pthread],[pthread_create],,[AC_MSG_ERROR([Could not find pthread_create!])]) +AC_CHECK_LIB([m],[sqrt],,[AC_MSG_ERROR([Could not find sqrt!])]) + + +AX_PROG_BISON_CLFEATURES([],[AC_MSG_WARN([Could not find bison])], +[bison_ok="yes"], [bison_ok="no"]) +AC_SUBST([bison_ok]) + +dnl Check to see if CC is an MPI compiler +AC_MSG_CHECKING(whether the mpicc compiler works) +AC_TRY_COMPILE([#include ], [int ret = MPI_Init(0, (void*)0)], + AC_MSG_RESULT(yes), + AC_MSG_RESULT(no) + AC_MSG_ERROR(CC doesnt appear to be a valid MPI compiler. See INSTALL document or try adding CC=mpicc to your configure command line.) +) + +# check for ROSS +PKG_CHECK_MODULES_STATIC([ROSS], [ross], [], + [AC_MSG_ERROR([Could not find working ross installation via pkg-config])]) + +# check for Darshan +AC_ARG_WITH([darshan],[AS_HELP_STRING([--with-darshan], + [Build with the darshan workload support])], + [use_darshan=yes],[use_darshan=no]) +if test "x${use_darshan}" = xyes ; then + PKG_CHECK_MODULES_STATIC([DARSHAN], [darshan-util], [], + [AC_MSG_ERROR([Could not find working darshan installation via pkg-config])]) + DARSHAN_VER=`pkg-config --modversion darshan-util` + AX_COMPARE_VERSION([$DARSHAN_VER],[ge],[2.3],[], + [AC_MSG_ERROR([Found Darshan $DARSHAN_VER but 2.3 or greater is needed])]) +fi +AM_CONDITIONAL(USE_DARSHAN, [test "x${use_darshan}" = xyes]) + + +# check for Recorder +AM_CONDITIONAL(USE_RECORDER, true) +RECORDER_CPPFLAGS="-DUSE_RECORDER=1" +AC_SUBST(RECORDER_CPPFLAGS) + +#check for Dumpi +AC_ARG_WITH([dumpi],[AS_HELP_STRING([--with-dumpi@<:@=DIR@:>@], + [location of Dumpi installation])]) +if test "x${with_dumpi}" != "x" ; then + AC_CHECK_FILE([${with_dumpi}/lib/libundumpi.la], + AM_CONDITIONAL(USE_DUMPI, true), + AC_MSG_ERROR(Could not find libundumpi.la)) + DUMPI_CFLAGS="-I${with_dumpi}/include" +# DUMPI_CFLAGS+=" -I${with_dumpi}/include/dumpi/common" +# DUMPI_CFLAGS+=" -I${with_dumpi}/include/dumpi/libdumpi" +# DUMPI_CFLAGS+=" -I${with_dumpi}/include/dumpi/libundumpi" + DUMPI_LIBS="-L${with_dumpi}/lib/ -lundumpi" + AC_SUBST(DUMPI_LIBS) + AC_SUBST(DUMPI_CFLAGS) +else + AM_CONDITIONAL(USE_DUMPI, false) +fi + +dnl ====================================================================== +dnl Try harder to be valgrind safe +dnl ====================================================================== +AC_ARG_ENABLE(valgrind-clean, + [AS_HELP_STRING( + [--enable-valgrind-clean], + [Try harder to avoid valgrind warnings]) + ]) + +AS_IF([test "x$enable_valgrind_clean" = "xyes"], [ + AC_DEFINE([VALGRIND], [1], [If enabling valgrind-clean build]) +]) + + +dnl AC_CONFIG_FILES([src/iokernellang/codesparser.y]) + +AC_CONFIG_FILES([Makefile]) + +AC_OUTPUT([maint/codes-base.pc]) + diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e7d8a4ac47179661f75e0df5ea40b16b6c6cde55 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,7 @@ +# latex files +*.aux +*.bbl +*.blg +*.log +# we don't want the output to be part of the repository +/codes-best-practices.pdf diff --git a/doc/BUILD_STEPS b/doc/BUILD_STEPS new file mode 100644 index 0000000000000000000000000000000000000000..3d49c9a8c9e239de1ab6d164f4e08cc81e6c311f --- /dev/null +++ b/doc/BUILD_STEPS @@ -0,0 +1,102 @@ +NOTE: see bottom of this file for suggested configurations on particular ANL +machines. + +0 - Checkout, build, and install the trunk version of ROSS +(https://github.com/carothersc/ROSS). At the time of +release (0.4.0), ROSS's latest commit hash was 44b7b9a, so this revision is +"safe" in the unlikely case incompatible changes come along in the future. If +working from the CODES master branches, use the ROSS master branch. + + git clone http://github.com/carothersc/ROSS.git + # if using 0.4.0 release: git checkout 44b7b9a + cd ROSS + mkdir build + cd build + # note: other options for ARCH include i386 (for 32 bit machines), + # bgp, and bgq (for Blue Gene systems) + ARCH=x86_64 CC=mpicc CXX=mpicxx cmake -DCMAKE_INSTALL_PREFIX=../install ../ + make -j 3 + make install + + + + For more details on installing ROSS, go to + https://github.com/carothersc/ROSS/blob/master/README.md . + + If using ccmake to configure, don't forget to set CMAKE_C_COMPILER and + CMAKE_CXX_COMPILER to mpicc/mpicxx + +1 - If you are building codes-base directly from the repository, run + + ./prepare.sh + +2 - Configure codes-base. This can be done in the source directory or in a + dedicated build directory if you prefer out-of-tree builds. The CC + environment variable must refer to an MPI compiler. + + mkdir build + cd build + ../configure --prefix=/path/to/codes-base/install CC=mpicc PKG_CONFIG_PATH=/path/to/ross/install/lib/pkgconfig + + To enable network tracing with dumpi + (http://sst.sandia.gov/about_dumpi.html), use the option + --with-dumpi=/path/to/dumpi/install with configure. + + NOTE: we only require libundumpi for trace processing. Hence, if building + dumpi from source you may configure with --disable-libdumpi and + --enable-libundumpi (this is especially useful if you have mpich3, which + breaks libdumpi's function wrappers through const'ifying the MPI + interface). + + Use the --with-darshan argument to configure to enable the optional + Darshan I/O workload generator + (http://www.mcs.anl.gov/research/projects/darshan/). In order to use + this option, you must either have the darshan-util portion + of Darshan installed in the default system path, or else add + /lib/pkgconfig to your PKG_CONFIG_PATH environment + variable before calling configure. + +3 - Build and install codes-base + + make && make install + +4 - (optional) run test programs + + make tests && make check + +5 - codes-base uses flex and bison (or lex and yacc) to generate several + parsers. These tools auto-generate C source files. To get around versioning + issues, we've distributed the auto-generated sources directly. To remove + all of the autogenerated files for these parsers, execute + + make maintainer-clean-local + + +Machine-specific configurations: +---------------- +- Fusion (ANL): add the following keys to your ~/.soft file and run "resoft" + prior to following the steps described in this file: + + +python-2.7.3 + +autoconf-2.68 + +git + +cmake + +Notes on using the clang static analyzer +----------------- +- follow steps 0-2 as shown above, with one exception: + - add the following argument to configure: + CFLAGS=-I +- edit Makefile, and delete the "CC = mpicc" (or similar) line +- run "scan-build --use-cc=mpicc make" + +Notes on using uncrustify +----------------- +- version 0.61 is required +- build/install uncrustify from your favorite distro (0.61), OR download from + https://github.com/bengardner/uncrustify and build from source + (configure --prefix /path/to/install && make && make install) +- either use uncrustify directly (see uncrustify --help) or use the provided + reformat.sh tool which is a shim over some of the options (see reformat.sh + -h) diff --git a/doc/GETTING_STARTED b/doc/GETTING_STARTED new file mode 100644 index 0000000000000000000000000000000000000000..b94c02c0f1e7eb0f4d15211f13360f790f55f8ae --- /dev/null +++ b/doc/GETTING_STARTED @@ -0,0 +1,377 @@ +This document serves the following purposes: +* Document project resources (repository links, etc.) +* Introduce and present an overview of the key components making up the CODES + library +* Walk through the CODES example model, which shows the majority of CODES + features currently available. + += CODES/ROSS resources + +CODES and ROSS share a mailing list. It is at: +https://lists.mcs.anl.gov/mailman/listinfo/codes-ross-users + +== CODES + +* main site: http://www.mcs.anl.gov/projects/codes/ +* repositories: + * "base" (this repository): git.mcs.anl.gov:radix/codes-base + * codes-net (networking component of CODES): git.mcs.anl.gov:radix/codes-net +* bug tracking: https://trac.mcs.anl.gov/projects/CODES + +== ROSS + +* main site, repository, etc.: https://github.com/carothersc/ROSS + * both the site and repository contain good documentation as well - refer to + it for an in-depth introduction and overview of ROSS proper + += Components of CODES + +== Configuration + +The configuration of LPs, LP parameterization, and miscellaneous simulation +parameters are specified by the CODES configuration system, which uses a +structured configuration file. The configuration format allows categories, and +optionally subgroups within the category, of key-value pairs for configuration. +The LPGROUPS category defines the LP configuration. The PARAMS category is +currently used for networking and ROSS-specific parameters. User-defined +categories can also be used. + +The configuration system additionally allows LP specialization via the usage of +"annotations". This allows two otherwise identical LPs to have different +parameterizations. Annotations have a simple "@" syntax appended to the LP +fields, and are optional. + +CODES currently exposes a small number of ROSS simulation engine options within +the configuration file. These are "PARAMS:message_size" and +"PARAMS:pe_mem_factor". The "message_size" parameter indicates the upper bound +of event sizes that ROSS is expected to handle, while the "pe_mem_factor" +parameter indicates the multiplier to the number of events allocated per ROSS +PE (an MPI rank). Both of these exist to support the static allocation scheme +ROSS uses for efficiency - both LP states and the maximum population of events +are allocated statically at the beginning of the simulation. + +The API is located at codes/configuration.h, which provides various types of +access into the simulation configuration. Detailed configuration files can be +found at doc/example/example.conf and doc/example_heterogeneous/example.conf. + +== LP mapping + +The codes-mapping API maps user LPs to global LP IDs, providing numerous +options for modulating the namespace under which the mapping is conducted. +Mapping is performed on a per-group or per-LP-type basis, with numerous further +filtering options including on an LPs annotation. Finally, the mapping API +provides LP counts using the aforementioned filtering options. + +The API can be found at codes/codes_mapping.h. doc/example/example.c shows a +simple example of the mapping functionality, while the test program +tests/mapping_test.c with configuration file tests/conf/mapping_test.conf +extensively demonstrates the mapping API. + +=== LP mapping context + +In many cases (the resource and local storage model LPs, and modelnet in +codes-net), the mapping from caller to callee LPs are implicit. The +codes-mapping context API (codes/codes-mapping-context.h) provides various +options for influencing these mappings, as well as providing the capability to +bypass codes-mapping and send messages directly to an LP. The test file +tests/map-ctx-test.c, along with the config file tests/conf/map-ctx-test.conf +provides the best usage examples. + +== LP messaging conventions + +Models in CODES that have a request-response form of communication resembling +that of RPCs follow a specific convention, defined in codes/codes-callback.h. +The header documents the convention. The current best example usage is in the +CODES sources themselves, i.e. in codes/resource-lp.h, src/util/resource-lp.c, +codes/local-storage-model.h, and src/util/local-storage-model.c. + +== Workload generator(s) + +codes-workload is an in-development abstraction layer for feeding I/O / network +workloads into a simulation. It supports multiple back-ends for generating I/O +and network events; data could come from a trace file, from Darshan, or from a +synthetic description. + +The workload generator is currently a work in progress, and the API is subject +to change. The I/O generation component exposes a "POSIX-ish" +open/close/read/write interface, while the network generation component exposes +an "MPI-ish" send/recv/barrier/collective interface. + +As an additional utility, we provide a simple debug program, +src/workload/codes-workload-dump, that processes a given workload and prints to +standard out. + +=== IO + +We currently have initial support for extrapolating (lossy) Darshan logs +(https://www.mcs.anl.gov/research/projects/darshan/), a simple synthetic IO +kernel language, and IO Recorder (https://github.com/babakbehzad/Recorder) +traces. + +==== Synthetic IO language + +The synthetic IO language is a simple, interpreted set of IO and basic +arithmetic commands meant to simplify the specification and running of +application workloads. + +The input for the workload generator consists of an IO kernel metadata file and +a number of IO kernel files. The former specifies a set of kernel files to run +and logical client IDs to participate in the workload, while the latter +describes the IO to be performed. + +The format of the metadata file is a set of lines containing: + +where: +* is the ID of this group (see restrictions) +* and form the range of logical client IDs that will + perform the given workload. Note that the end ID is inclusive, so a start, + end pair of 0, 3 will include IDs 0, 1, 2, and 3. An of -1 indicates + to use the remaining number of clients as specified by the user. +* is the path to the IO kernel workload. It may either be an + absolute or relative path. + +The IO kernel file contains a set of commands performed on a per-client +basis. Like the workload generator interface, files are represented by integer +IDs, and the standard set of "POSIX-ish" operations can be applied (e.g., open, +close, sync, write, read) and have a similar argument list (file ID, [length], +[offset] where applicable). pread/pwrite equivalents are given by +readat/writeat. + +More detailed documentation on the language is ongoing, but for now a general +example can be seen at doc/workload, which shows a simple out-of-core data +shuffle. Braver souls may wish to visit the implementation at src/iokernellang +and src/workload/codes-iolang-wrkld.c. + +The following restrictions currently apply to the IO language: +* all user-defined variables must be a single, lower-case letter (the symbol + table from the code we inherited is an array of 26 chars) +* the implementation of "groups" is currently broken. We have gotten around + this by hard-coding in the group size and client ID into the parser when a + kernel file is loaded (parsing currently occurs on a per-client basis). + Hence, getgroupid should be completely ignored and getgrouprank and + getgroupsize ignore the group ID parameter passed in. + +=== Network + +Our primary network workload generator is via the DUMPI tool +(http://sst.sandia.gov/about_dumpi.html). DUMPI collects and reads events from +MPI applications. See the DUMPI documentation for how to generate traces. There +are additionally publically-available traces at +http://portal.nersc.gov/project/CAL/doe-miniapps.htm. + +Note on trace reading - the input file prefix to the dumpi workload generator +should be everything up to the rank number. E.g., if the dumpi files are of the +form "dumpi-YYYY.MM.DD.HH.MM.SS-XXXX.bin", then the input should be +"dumpi-YYYY.MM.DD.HH.MM.SS-" + +=== Workload generator helpers + +The codes-jobmap API (codes/codes-jobmap.h) specifies mechanisms to initialize +and run multiple jobs with unique job IDs and linear namespaces, used to allow +multiple concurrent workloads to be run within the same simulation. Example +usage can be seen in tests/jobmap-test.c and, for the list allocation method, +in tests/conf/jobmap-test-list.conf. Note that only the DUMPI trace generator +has been tested using this interface at this time. + +== LP-IO + +LP-IO is a set of simple reverse-computation-aware routines for conditionally +outputting data on a per-LP basis. As the focus is on convenient, small-scale +data output, data written via LP-IO remains in memory until the end of the +simulation, or freed upon reverse computation. Large-scale, +reverse-computation-aware IO is a feature we're thinking about for future +usage. + +The API can be found at codes/lp-io.h and is fairly self-explanatory. + +== CODES configurator + +The configurator is a set of scripts intended to make the auto-generation of +multiple CODES configuration files easier, for the purposes of performing +parameter sweeps of simulations. The configuration file defining the parameters +in the parameter sweep is defined by a python source file with well-defined +field names, to maximize flexibility and enable some essential features for +flexible parameter sweeps (disabling certain combinations of parameters, +deriving parameters from other parameters in the sweep). The actual replacement +is driven by token replacement defined by the values in the configuration file. + +An exhaustive example can be found at scripts/example. The scripts themselves +are codes_configurator.py, codes_filter_configs.py, and +codes_config_get_vals.py, each with detailed usage info. These scripts have +heavily-overlapping functionality, so in the future these may be merged. + +== Miscellaneous utilities + +=== Workload display utility + +For debugging and experimentation purposes, a plain-text "dump" of an IO +workload can be seen using the utility src/workload/codes-workload-dump +(it gets installed into $bindir). + +=== LP template (src/util/templates) + +As writing ROSS/CODES models currently entail a not-insignificant amount of +boilerplate for defining LPs and hooking them into ROSS, we have a template +model for use at src/util/templates/lp_template.* . + +=== Generic message header (see best practices) + +We recommend the use of codes/lp-msg.h to standardize LP event headers, making it +easier to identify messages. + += Utility models + +== Local storage model + +The local storage model (LSM) is fairly simple in design but is sufficient for +many simulations with reasonable I/O access patterns. It is an +overhead/latency/bandwidth model that tracks file and offset accesses to +determine whether to apply seeking penalties to the performance of the access. +It uses a simple histogram-based approach to parameterization: +overhead/latency/bandwidth numbers are given relative to different access +sizes. To gather such parameters, well-known I/O benchmarks such as fio +(http://git.kernel.dk/?p=fio.git;a=summary) can be used. + +The LP name used in configuration is "lsm" and the configuration is expected to +be in a similarly named standalone group, an example of which is shown below: + +lsm +{ + # in bytes + request_sizes = ( "4096","8192","16384","32768","65536","131072","262144","524288","1048576","2097152","4194304" ); + # in MiB/s (2^20 bytes / s) + write_rates = ( "1511.7","1511.7","1511.7","1511.7","1511.7","1511.7","1511.7","1511.7","1511.7","1511.7","1511.7" ); + read_rates = ( "1542.1","1542.1","1542.1","1542.1","1542.1","1542.1","1542.1","1542.1","1542.1","1542.1","1542.1" ); + # in microseconds + write_seeks = ( "499.5","509.0","514.7","525.9","546.4","588.3","663.1","621.8","539.1","3179.5","6108.8" ); + read_seeks = ( "3475.6","3470.0","3486.2","3531.2","3608.6","3741.0","3988.9","4530.2","5644.2","7922.0","11700.3" ); + write_overheads = ( "29.67","29.67","29.67","29.67","29.67","29.67","29.67","29.67","29.67","29.67","29.67" ); + read_overheads = ( "23.67","23.67","23.67","23.67","23.67","23.67","23.67","23.67","23.67","23.67","23.67" ); +} + +The API can be found at codes/local-storage-model.h and example usage can be +seen in tests/local-storage-model-test.c and tests/conf/lsm-test.conf. + +The queueing policy of LSM is currently FIFO, and the default mode uses an +implicit queue, simply incrementing counters and scheduling future events when +I/O requests come in. Additionally, an explicit queue has been added and +provides a simple FIFO+priority mechanism. To use, in the "lsm" group set +"enable_scheduler" to the value "1". + +== Resource model + +The resource model presents a simple integer counter representing some finite +resource (e.g., bytes of memory available). LPs request some number of units of +the resource, receiving a success/failure completion message via a callback +mechanism. Optional "blocking" can be used to defer the completion message +until the request is successfully completed. + +The configuration LP name is "resource" and the parameters are given in a +similarly-named group. An example is shown below: + +resource +{ + available="8192"; +} + +The API for the underlying resource data structure can be found in +codes/resource.h. The user-facing API for communicating with the LP can be +found in codes/resource-lp.h. + += CODES example model + +An example model representing most of the functionality present in CODES is +available in doc/example. In this scenario, we have a certain number of storage +servers, identified through indices 0, ... , n-1 where each server has a +network interface card (NIC) associated with it. The servers exchange messages +with their neighboring server via their NIC card (i.e., server i pings server +i+1, rolling over the index if necessary). When the neighboring server receives +the message, it sends an acknowledgement message to the sending server in +response. Upon receiving the acknowledgement, the sending server issues another +message. This process continues until some number of messages have been sent. +For simplicity, it is assumed that each server has a direct link to its +neighbor, and no network congestion occurs due to concurrent messages being +sent. + +The model is relatively simple to simulate through the usage of ROSS. There are +two distinct LP types in the simulation: the server and the NIC. Refer to +example.c for data structure definitions. The server LPs are in charge of +issuing/acknowledging the messages, while the NIC LPs (implemented via CODES's +model-net component, available in the codes-net repository) transmit the data +and inform their corresponding servers upon completion. This LP decomposition +strategy is generally preferred for ROSS-based simulations: have +single-purpose, simple LPs representing logical system components. + +In this program, CODES is used in the following four ways: to provide +configuration utilities for the program (example.conf), to logically separate +and provide lookup functionality for multiple LP types, to automate LP +placement on KPs/PEs, and to simplify/modularize the underlying network +structure. The configuration API is used for the first use-case, the +mapping API is used for the second and third use-cases, and the +model-net API is used for the fourth use-case. The following sections +discuss these while covering necessary ROSS-specific information. + +== Configuration and mapping + +In the example program, there are one server LP and one +"modelnet_simplenet" LP type in a group and this combination is +repeated 16 times (repetitions="16") for a total of 32 LPs. The section +"server_pings" is server-LP-specific and defines the number of rounds of +communication and the payload for each round. + +We use the simple-net LP provided by model-net as the underlying network +model. The simple-net parameters are specified by the user in the PARAMS +section of the example.conf config file. + +== Server state and event handlers + +The server LP state maintains a count of the number of remote messages it has +sent and received as well as the number of local completion messages. + +For the server event message, we have four message types: KICKOFF, REQ, ACK and +LOCAL. With a KICKOFF event, each LP sends a message to itself to begin the +simulation proper. To avoid event ties, we add a small amount of random noise +using codes_local_latency. The REQ message is sent by a server to its +neighboring server and when received, neighboring server sends back a message +of type ACK. We've shown a hard-coded direct communication method which +directly computes the LP ID, and a codes-mapping API-based method. + +== Server reverse computation + +ROSS has the capability for optimistic parallel simulation, but instead of +saving the state of each LP, they instead require users to perform reverse +computation. That is, while the event messages are themselves preserved (until +the Global Virtual Time (GVT) algorithm renders the messages unneeded), the LP +state is not preserved. Hence, it is up to the simulation developer to provide +functionality to reverse the LP state, given the event to be reversed. ROSS +makes this simpler in that events will always be rolled back in exactly the +order they were applied. Note that ROSS also has both serial and parallel +conservative modes, so reverse computation may not be necessary if the +simulation is not compute- or memory-intensive. + +For our example program, recall the "forward" event handlers. They perform the +following: +* Kickoff: send a message to the peer server, and increment sender LP's + count of sent messages. +* Request (received from peer server): increment receiver count of + received messages, and send an acknowledgement to the sender. +* Acknowledgement (received from message receiver): send the next + message to the receiver and increment messages sent count. Set a flag + indicating whether a message has been sent. +* Local model-net callback: increment the local model-net + received messages count. + +In terms of LP state, the four operations are simply modifying counts. Hence, +the "reverse" event handlers need to merely roll back those changes: +* Kickoff: decrement sender LP's count of sent messages. +* Request (received from peer server): decrement receiver count of + received messages. +* Acknowledgement (received from message receiver): decrement messages + sent count if flag indicating a message has been sent has not been + set. +* Local model-net callback: decrement the local model-net + received messages count. + +For more complex LP states (such as maintaining queues), reverse event +processing becomes similarly more complex. Refer to the best practices document +for strategies of coping with the increase in complexity. diff --git a/doc/IEEEtran.cls b/doc/IEEEtran.cls new file mode 100644 index 0000000000000000000000000000000000000000..56817146a5b70ed08be5066430495b60eb2ac5cc --- /dev/null +++ b/doc/IEEEtran.cls @@ -0,0 +1,4702 @@ +%% +%% IEEEtran.cls 2007/03/05 version V1.7a +%% +%% +%% This is the official IEEE LaTeX class for authors of the Institute of +%% Electrical and Electronics Engineers (IEEE) Transactions journals and +%% conferences. +%% +%% Support sites: +%% http://www.michaelshell.org/tex/ieeetran/ +%% http://www.ctan.org/tex-archive/macros/latex/contrib/IEEEtran/ +%% and +%% http://www.ieee.org/ +%% +%% Based on the original 1993 IEEEtran.cls, but with many bug fixes +%% and enhancements (from both JVH and MDS) over the 1996/7 version. +%% +%% +%% Contributors: +%% Gerry Murray (1993), Silvano Balemi (1993), +%% Jon Dixon (1996), Peter N"uchter (1996), +%% Juergen von Hagen (2000), and Michael Shell (2001-2007) +%% +%% +%% Copyright (c) 1993-2000 by Gerry Murray, Silvano Balemi, +%% Jon Dixon, Peter N"uchter, +%% Juergen von Hagen +%% and +%% Copyright (c) 2001-2007 by Michael Shell +%% +%% Current maintainer (V1.3 to V1.7): Michael Shell +%% See: +%% http://www.michaelshell.org/ +%% for current contact information. +%% +%% Special thanks to Peter Wilson (CUA) and Donald Arseneau +%% for allowing the inclusion of the \@ifmtarg command +%% from their ifmtarg LaTeX package. +%% +%%************************************************************************* +%% Legal Notice: +%% This code is offered as-is without any warranty either expressed or +%% implied; without even the implied warranty of MERCHANTABILITY or +%% FITNESS FOR A PARTICULAR PURPOSE! +%% User assumes all risk. +%% In no event shall IEEE or any contributor to this code be liable for +%% any damages or losses, including, but not limited to, incidental, +%% consequential, or any other damages, resulting from the use or misuse +%% of any information contained here. +%% +%% All comments are the opinions of their respective authors and are not +%% necessarily endorsed by the IEEE. +%% +%% This work is distributed under the LaTeX Project Public License (LPPL) +%% ( http://www.latex-project.org/ ) version 1.3, and may be freely used, +%% distributed and modified. A copy of the LPPL, version 1.3, is included +%% in the base LaTeX documentation of all distributions of LaTeX released +%% 2003/12/01 or later. +%% Retain all contribution notices and credits. +%% ** Modified files should be clearly indicated as such, including ** +%% ** renaming them and changing author support contact information. ** +%% +%% File list of work: IEEEtran.cls, IEEEtran_HOWTO.pdf, bare_adv.tex, +%% bare_conf.tex, bare_jrnl.tex, bare_jrnl_compsoc.tex +%% +%% Major changes to the user interface should be indicated by an +%% increase in the version numbers. If a version is a beta, it will +%% be indicated with a BETA suffix, i.e., 1.4 BETA. +%% Small changes can be indicated by appending letters to the version +%% such as "IEEEtran_v14a.cls". +%% In all cases, \Providesclass, any \typeout messages to the user, +%% \IEEEtransversionmajor and \IEEEtransversionminor must reflect the +%% correct version information. +%% The changes should also be documented via source comments. +%%************************************************************************* +%% +% +% Available class options +% e.g., \documentclass[10pt,conference]{IEEEtran} +% +% *** choose only one from each category *** +% +% 9pt, 10pt, 11pt, 12pt +% Sets normal font size. The default is 10pt. +% +% conference, journal, technote, peerreview, peerreviewca +% determines format mode - conference papers, journal papers, +% correspondence papers (technotes), or peer review papers. The user +% should also select 9pt when using technote. peerreview is like +% journal mode, but provides for a single-column "cover" title page for +% anonymous peer review. The paper title (without the author names) is +% repeated at the top of the page after the cover page. For peer review +% papers, the \IEEEpeerreviewmaketitle command must be executed (will +% automatically be ignored for non-peerreview modes) at the place the +% cover page is to end, usually just after the abstract (keywords are +% not normally used with peer review papers). peerreviewca is like +% peerreview, but allows the author names to be entered and formatted +% as with conference mode so that author affiliation and contact +% information can be easily seen on the cover page. +% The default is journal. +% +% draft, draftcls, draftclsnofoot, final +% determines if paper is formatted as a widely spaced draft (for +% handwritten editor comments) or as a properly typeset final version. +% draftcls restricts draft mode to the class file while all other LaTeX +% packages (i.e., \usepackage{graphicx}) will behave as final - allows +% for a draft paper with visible figures, etc. draftclsnofoot is like +% draftcls, but does not display the date and the word "DRAFT" at the foot +% of the pages. If using one of the draft modes, the user will probably +% also want to select onecolumn. +% The default is final. +% +% letterpaper, a4paper +% determines paper size: 8.5in X 11in or 210mm X 297mm. CHANGING THE PAPER +% SIZE WILL NOT ALTER THE TYPESETTING OF THE DOCUMENT - ONLY THE MARGINS +% WILL BE AFFECTED. In particular, documents using the a4paper option will +% have reduced side margins (A4 is narrower than US letter) and a longer +% bottom margin (A4 is longer than US letter). For both cases, the top +% margins will be the same and the text will be horizontally centered. +% For final submission to IEEE, authors should use US letter (8.5 X 11in) +% paper. Note that authors should ensure that all post-processing +% (ps, pdf, etc.) uses the same paper specificiation as the .tex document. +% Problems here are by far the number one reason for incorrect margins. +% IEEEtran will automatically set the default paper size under pdflatex +% (without requiring a change to pdftex.cfg), so this issue is more +% important to dvips users. Fix config.ps, config.pdf, or ~/.dvipsrc for +% dvips, or use the dvips -t papersize option instead as needed. See the +% testflow documentation +% http://www.ctan.org/tex-archive/macros/latex/contrib/IEEEtran/testflow +% for more details on dvips paper size configuration. +% The default is letterpaper. +% +% oneside, twoside +% determines if layout follows single sided or two sided (duplex) +% printing. The only notable change is with the headings at the top of +% the pages. +% The default is oneside. +% +% onecolumn, twocolumn +% determines if text is organized into one or two columns per page. One +% column mode is usually used only with draft papers. +% The default is twocolumn. +% +% compsoc +% Use the format of the IEEE Computer Society. +% +% romanappendices +% Use the "Appendix I" convention when numbering appendices. IEEEtran.cls +% now defaults to Alpha "Appendix A" convention - the opposite of what +% v1.6b and earlier did. +% +% captionsoff +% disables the display of the figure/table captions. Some IEEE journals +% request that captions be removed and figures/tables be put on pages +% of their own at the end of an initial paper submission. The endfloat +% package can be used with this class option to achieve this format. +% +% nofonttune +% turns off tuning of the font interword spacing. Maybe useful to those +% not using the standard Times fonts or for those who have already "tuned" +% their fonts. +% The default is to enable IEEEtran to tune font parameters. +% +% +%---------- +% Available CLASSINPUTs provided (all are macros unless otherwise noted): +% \CLASSINPUTbaselinestretch +% \CLASSINPUTinnersidemargin +% \CLASSINPUToutersidemargin +% \CLASSINPUTtoptextmargin +% \CLASSINPUTbottomtextmargin +% +% Available CLASSINFOs provided: +% \ifCLASSINFOpdf (TeX if conditional) +% \CLASSINFOpaperwidth (macro) +% \CLASSINFOpaperheight (macro) +% \CLASSINFOnormalsizebaselineskip (length) +% \CLASSINFOnormalsizeunitybaselineskip (length) +% +% Available CLASSOPTIONs provided: +% all class option flags (TeX if conditionals) unless otherwise noted, +% e.g., \ifCLASSOPTIONcaptionsoff +% point size options provided as a single macro: +% \CLASSOPTIONpt +% which will be defined as 9, 10, 11, or 12 depending on the document's +% normalsize point size. +% also, class option peerreviewca implies the use of class option peerreview +% and classoption draft implies the use of class option draftcls + + + + + +\ProvidesClass{IEEEtran}[2007/03/05 V1.7a by Michael Shell] +\typeout{-- See the "IEEEtran_HOWTO" manual for usage information.} +\typeout{-- http://www.michaelshell.org/tex/ieeetran/} +\NeedsTeXFormat{LaTeX2e} + +% IEEEtran.cls version numbers, provided as of V1.3 +% These values serve as a way a .tex file can +% determine if the new features are provided. +% The version number of this IEEEtrans.cls can be obtained from +% these values. i.e., V1.4 +% KEEP THESE AS INTEGERS! i.e., NO {4a} or anything like that- +% (no need to enumerate "a" minor changes here) +\def\IEEEtransversionmajor{1} +\def\IEEEtransversionminor{7} + +% These do nothing, but provide them like in article.cls +\newif\if@restonecol +\newif\if@titlepage + + +% class option conditionals +\newif\ifCLASSOPTIONonecolumn \CLASSOPTIONonecolumnfalse +\newif\ifCLASSOPTIONtwocolumn \CLASSOPTIONtwocolumntrue + +\newif\ifCLASSOPTIONoneside \CLASSOPTIONonesidetrue +\newif\ifCLASSOPTIONtwoside \CLASSOPTIONtwosidefalse + +\newif\ifCLASSOPTIONfinal \CLASSOPTIONfinaltrue +\newif\ifCLASSOPTIONdraft \CLASSOPTIONdraftfalse +\newif\ifCLASSOPTIONdraftcls \CLASSOPTIONdraftclsfalse +\newif\ifCLASSOPTIONdraftclsnofoot \CLASSOPTIONdraftclsnofootfalse + +\newif\ifCLASSOPTIONpeerreview \CLASSOPTIONpeerreviewfalse +\newif\ifCLASSOPTIONpeerreviewca \CLASSOPTIONpeerreviewcafalse + +\newif\ifCLASSOPTIONjournal \CLASSOPTIONjournaltrue +\newif\ifCLASSOPTIONconference \CLASSOPTIONconferencefalse +\newif\ifCLASSOPTIONtechnote \CLASSOPTIONtechnotefalse + +\newif\ifCLASSOPTIONnofonttune \CLASSOPTIONnofonttunefalse + +\newif\ifCLASSOPTIONcaptionsoff \CLASSOPTIONcaptionsofffalse + +\newif\ifCLASSOPTIONcompsoc \CLASSOPTIONcompsocfalse + +\newif\ifCLASSOPTIONromanappendices \CLASSOPTIONromanappendicesfalse + + +% class info conditionals + +% indicates if pdf (via pdflatex) output +\newif\ifCLASSINFOpdf \CLASSINFOpdffalse + + +% V1.6b internal flag to show if using a4paper +\newif\if@IEEEusingAfourpaper \@IEEEusingAfourpaperfalse + + + +% IEEEtran class scratch pad registers +% dimen +\newdimen\@IEEEtrantmpdimenA +\newdimen\@IEEEtrantmpdimenB +% count +\newcount\@IEEEtrantmpcountA +\newcount\@IEEEtrantmpcountB +% token list +\newtoks\@IEEEtrantmptoksA + +% we use \CLASSOPTIONpt so that we can ID the point size (even for 9pt docs) +% as well as LaTeX's \@ptsize to retain some compatability with some +% external packages +\def\@ptsize{0} +% LaTeX does not support 9pt, so we set \@ptsize to 0 - same as that of 10pt +\DeclareOption{9pt}{\def\CLASSOPTIONpt{9}\def\@ptsize{0}} +\DeclareOption{10pt}{\def\CLASSOPTIONpt{10}\def\@ptsize{0}} +\DeclareOption{11pt}{\def\CLASSOPTIONpt{11}\def\@ptsize{1}} +\DeclareOption{12pt}{\def\CLASSOPTIONpt{12}\def\@ptsize{2}} + + + +\DeclareOption{letterpaper}{\setlength{\paperheight}{11in}% + \setlength{\paperwidth}{8.5in}% + \@IEEEusingAfourpaperfalse + \def\CLASSOPTIONpaper{letter}% + \def\CLASSINFOpaperwidth{8.5in}% + \def\CLASSINFOpaperheight{11in}} + + +\DeclareOption{a4paper}{\setlength{\paperheight}{297mm}% + \setlength{\paperwidth}{210mm}% + \@IEEEusingAfourpapertrue + \def\CLASSOPTIONpaper{a4}% + \def\CLASSINFOpaperwidth{210mm}% + \def\CLASSINFOpaperheight{297mm}} + +\DeclareOption{oneside}{\@twosidefalse\@mparswitchfalse + \CLASSOPTIONonesidetrue\CLASSOPTIONtwosidefalse} +\DeclareOption{twoside}{\@twosidetrue\@mparswitchtrue + \CLASSOPTIONtwosidetrue\CLASSOPTIONonesidefalse} + +\DeclareOption{onecolumn}{\CLASSOPTIONonecolumntrue\CLASSOPTIONtwocolumnfalse} +\DeclareOption{twocolumn}{\CLASSOPTIONtwocolumntrue\CLASSOPTIONonecolumnfalse} + +% If the user selects draft, then this class AND any packages +% will go into draft mode. +\DeclareOption{draft}{\CLASSOPTIONdrafttrue\CLASSOPTIONdraftclstrue + \CLASSOPTIONdraftclsnofootfalse} +% draftcls is for a draft mode which will not affect any packages +% used by the document. +\DeclareOption{draftcls}{\CLASSOPTIONdraftfalse\CLASSOPTIONdraftclstrue + \CLASSOPTIONdraftclsnofootfalse} +% draftclsnofoot is like draftcls, but without the footer. +\DeclareOption{draftclsnofoot}{\CLASSOPTIONdraftfalse\CLASSOPTIONdraftclstrue + \CLASSOPTIONdraftclsnofoottrue} +\DeclareOption{final}{\CLASSOPTIONdraftfalse\CLASSOPTIONdraftclsfalse + \CLASSOPTIONdraftclsnofootfalse} + +\DeclareOption{journal}{\CLASSOPTIONpeerreviewfalse\CLASSOPTIONpeerreviewcafalse + \CLASSOPTIONjournaltrue\CLASSOPTIONconferencefalse\CLASSOPTIONtechnotefalse} + +\DeclareOption{conference}{\CLASSOPTIONpeerreviewfalse\CLASSOPTIONpeerreviewcafalse + \CLASSOPTIONjournalfalse\CLASSOPTIONconferencetrue\CLASSOPTIONtechnotefalse} + +\DeclareOption{technote}{\CLASSOPTIONpeerreviewfalse\CLASSOPTIONpeerreviewcafalse + \CLASSOPTIONjournalfalse\CLASSOPTIONconferencefalse\CLASSOPTIONtechnotetrue} + +\DeclareOption{peerreview}{\CLASSOPTIONpeerreviewtrue\CLASSOPTIONpeerreviewcafalse + \CLASSOPTIONjournalfalse\CLASSOPTIONconferencefalse\CLASSOPTIONtechnotefalse} + +\DeclareOption{peerreviewca}{\CLASSOPTIONpeerreviewtrue\CLASSOPTIONpeerreviewcatrue + \CLASSOPTIONjournalfalse\CLASSOPTIONconferencefalse\CLASSOPTIONtechnotefalse} + +\DeclareOption{nofonttune}{\CLASSOPTIONnofonttunetrue} + +\DeclareOption{captionsoff}{\CLASSOPTIONcaptionsofftrue} + +\DeclareOption{compsoc}{\CLASSOPTIONcompsoctrue} + +\DeclareOption{romanappendices}{\CLASSOPTIONromanappendicestrue} + + +% default to US letter paper, 10pt, twocolumn, one sided, final, journal +\ExecuteOptions{letterpaper,10pt,twocolumn,oneside,final,journal} +% overrride these defaults per user requests +\ProcessOptions + + + +% Computer Society conditional execution command +\long\def\@IEEEcompsoconly#1{\relax\ifCLASSOPTIONcompsoc\relax#1\relax\fi\relax} +% inverse +\long\def\@IEEEnotcompsoconly#1{\relax\ifCLASSOPTIONcompsoc\else\relax#1\relax\fi\relax} +% compsoc conference +\long\def\@IEEEcompsocconfonly#1{\relax\ifCLASSOPTIONcompsoc\ifCLASSOPTIONconference\relax#1\relax\fi\fi\relax} +% compsoc not conference +\long\def\@IEEEcompsocnotconfonly#1{\relax\ifCLASSOPTIONcompsoc\ifCLASSOPTIONconference\else\relax#1\relax\fi\fi\relax} + + +% IEEE uses Times Roman font, so we'll default to Times. +% These three commands make up the entire times.sty package. +\renewcommand{\sfdefault}{phv} +\renewcommand{\rmdefault}{ptm} +\renewcommand{\ttdefault}{pcr} + +\@IEEEcompsoconly{\typeout{-- Using IEEE Computer Society mode.}} + +% V1.7 compsoc nonconference papers, use Palatino/Palladio as the main text font, +% not Times Roman. +\@IEEEcompsocnotconfonly{\renewcommand{\rmdefault}{ppl}} + +% enable Times/Palatino main text font +\normalfont\selectfont + + + + + +% V1.7 conference notice message hook +\def\@IEEEconsolenoticeconference{\typeout{}% +\typeout{** Conference Paper **}% +\typeout{Before submitting the final camera ready copy, remember to:}% +\typeout{}% +\typeout{ 1. Manually equalize the lengths of two columns on the last page}% +\typeout{ of your paper;}% +\typeout{}% +\typeout{ 2. Ensure that any PostScript and/or PDF output post-processing}% +\typeout{ uses only Type 1 fonts and that every step in the generation}% +\typeout{ process uses the appropriate paper size.}% +\typeout{}} + + +% we can send console reminder messages to the user here +\AtEndDocument{\ifCLASSOPTIONconference\@IEEEconsolenoticeconference\fi} + + +% warn about the use of single column other than for draft mode +\ifCLASSOPTIONtwocolumn\else% + \ifCLASSOPTIONdraftcls\else% + \typeout{** ATTENTION: Single column mode is not typically used with IEEE publications.}% + \fi% +\fi + + +% V1.7 improved paper size setting code. +% Set pdfpage and dvips paper sizes. Conditional tests are similar to that +% of ifpdf.sty. Retain within {} to ensure tested macros are never altered, +% even if only effect is to set them to \relax. +% if \pdfoutput is undefined or equal to relax, output a dvips special +{\@ifundefined{pdfoutput}{\AtBeginDvi{\special{papersize=\CLASSINFOpaperwidth,\CLASSINFOpaperheight}}}{% +% pdfoutput is defined and not equal to \relax +% check for pdfpageheight existence just in case someone sets pdfoutput +% under non-pdflatex. If exists, set them regardless of value of \pdfoutput. +\@ifundefined{pdfpageheight}{\relax}{\global\pdfpagewidth\paperwidth +\global\pdfpageheight\paperheight}% +% if using \pdfoutput=0 under pdflatex, send dvips papersize special +\ifcase\pdfoutput +\AtBeginDvi{\special{papersize=\CLASSINFOpaperwidth,\CLASSINFOpaperheight}}% +\else +% we are using pdf output, set CLASSINFOpdf flag +\global\CLASSINFOpdftrue +\fi}} + +% let the user know the selected papersize +\typeout{-- Using \CLASSINFOpaperwidth\space x \CLASSINFOpaperheight\space +(\CLASSOPTIONpaper)\space paper.} + +\ifCLASSINFOpdf +\typeout{-- Using PDF output.} +\else +\typeout{-- Using DVI output.} +\fi + + +% The idea hinted here is for LaTeX to generate markleft{} and markright{} +% automatically for you after you enter \author{}, \journal{}, +% \journaldate{}, journalvol{}, \journalnum{}, etc. +% However, there may be some backward compatibility issues here as +% well as some special applications for IEEEtran.cls and special issues +% that may require the flexible \markleft{}, \markright{} and/or \markboth{}. +% We'll leave this as an open future suggestion. +%\newcommand{\journal}[1]{\def\@journal{#1}} +%\def\@journal{} + + + +% pointsize values +% used with ifx to determine the document's normal size +\def\@IEEEptsizenine{9} +\def\@IEEEptsizeten{10} +\def\@IEEEptsizeeleven{11} +\def\@IEEEptsizetwelve{12} + + + +% FONT DEFINITIONS (No sizexx.clo file needed) +% V1.6 revised font sizes, displayskip values and +% revised normalsize baselineskip to reduce underfull vbox problems +% on the 58pc = 696pt = 9.5in text height we want +% normalsize #lines/column baselineskip (aka leading) +% 9pt 63 11.0476pt (truncated down) +% 10pt 58 12pt (exact) +% 11pt 52 13.3846pt (truncated down) +% 12pt 50 13.92pt (exact) +% + +% we need to store the nominal baselineskip for the given font size +% in case baselinestretch ever changes. +% this is a dimen, so it will not hold stretch or shrink +\newdimen\@IEEEnormalsizeunitybaselineskip +\@IEEEnormalsizeunitybaselineskip\baselineskip + +\ifx\CLASSOPTIONpt\@IEEEptsizenine +\typeout{-- This is a 9 point document.} +\def\normalsize{\@setfontsize{\normalsize}{9}{11.0476pt}}% +\setlength{\@IEEEnormalsizeunitybaselineskip}{11.0476pt}% +\normalsize +\abovedisplayskip 1.5ex plus3pt minus1pt% +\belowdisplayskip \abovedisplayskip% +\abovedisplayshortskip 0pt plus3pt% +\belowdisplayshortskip 1.5ex plus3pt minus1pt +\def\small{\@setfontsize{\small}{8.5}{10pt}} +\def\footnotesize{\@setfontsize{\footnotesize}{8}{9pt}} +\def\scriptsize{\@setfontsize{\scriptsize}{7}{8pt}} +\def\tiny{\@setfontsize{\tiny}{5}{6pt}} +% sublargesize is the same as large - 10pt +\def\sublargesize{\@setfontsize{\sublargesize}{10}{12pt}} +\def\large{\@setfontsize{\large}{10}{12pt}} +\def\Large{\@setfontsize{\Large}{12}{14pt}} +\def\LARGE{\@setfontsize{\LARGE}{14}{17pt}} +\def\huge{\@setfontsize{\huge}{17}{20pt}} +\def\Huge{\@setfontsize{\Huge}{20}{24pt}} +\fi + + +% Check if we have selected 10 points +\ifx\CLASSOPTIONpt\@IEEEptsizeten +\typeout{-- This is a 10 point document.} +\def\normalsize{\@setfontsize{\normalsize}{10}{12.00pt}}% +\setlength{\@IEEEnormalsizeunitybaselineskip}{12pt}% +\normalsize +\abovedisplayskip 1.5ex plus4pt minus2pt% +\belowdisplayskip \abovedisplayskip% +\abovedisplayshortskip 0pt plus4pt% +\belowdisplayshortskip 1.5ex plus4pt minus2pt +\def\small{\@setfontsize{\small}{9}{10pt}} +\def\footnotesize{\@setfontsize{\footnotesize}{8}{9pt}} +\def\scriptsize{\@setfontsize{\scriptsize}{7}{8pt}} +\def\tiny{\@setfontsize{\tiny}{5}{6pt}} +% sublargesize is a tad smaller than large - 11pt +\def\sublargesize{\@setfontsize{\sublargesize}{11}{13.4pt}} +\def\large{\@setfontsize{\large}{12}{14pt}} +\def\Large{\@setfontsize{\Large}{14}{17pt}} +\def\LARGE{\@setfontsize{\LARGE}{17}{20pt}} +\def\huge{\@setfontsize{\huge}{20}{24pt}} +\def\Huge{\@setfontsize{\Huge}{24}{28pt}} +\fi + + +% Check if we have selected 11 points +\ifx\CLASSOPTIONpt\@IEEEptsizeeleven +\typeout{-- This is an 11 point document.} +\def\normalsize{\@setfontsize{\normalsize}{11}{13.3846pt}}% +\setlength{\@IEEEnormalsizeunitybaselineskip}{13.3846pt}% +\normalsize +\abovedisplayskip 1.5ex plus5pt minus3pt% +\belowdisplayskip \abovedisplayskip% +\abovedisplayshortskip 0pt plus5pt% +\belowdisplayshortskip 1.5ex plus5pt minus3pt +\def\small{\@setfontsize{\small}{10}{12pt}} +\def\footnotesize{\@setfontsize{\footnotesize}{9}{10.5pt}} +\def\scriptsize{\@setfontsize{\scriptsize}{8}{9pt}} +\def\tiny{\@setfontsize{\tiny}{6}{7pt}} +% sublargesize is the same as large - 12pt +\def\sublargesize{\@setfontsize{\sublargesize}{12}{14pt}} +\def\large{\@setfontsize{\large}{12}{14pt}} +\def\Large{\@setfontsize{\Large}{14}{17pt}} +\def\LARGE{\@setfontsize{\LARGE}{17}{20pt}} +\def\huge{\@setfontsize{\huge}{20}{24pt}} +\def\Huge{\@setfontsize{\Huge}{24}{28pt}} +\fi + + +% Check if we have selected 12 points +\ifx\CLASSOPTIONpt\@IEEEptsizetwelve +\typeout{-- This is a 12 point document.} +\def\normalsize{\@setfontsize{\normalsize}{12}{13.92pt}}% +\setlength{\@IEEEnormalsizeunitybaselineskip}{13.92pt}% +\normalsize +\abovedisplayskip 1.5ex plus6pt minus4pt% +\belowdisplayskip \abovedisplayskip% +\abovedisplayshortskip 0pt plus6pt% +\belowdisplayshortskip 1.5ex plus6pt minus4pt +\def\small{\@setfontsize{\small}{10}{12pt}} +\def\footnotesize{\@setfontsize{\footnotesize}{9}{10.5pt}} +\def\scriptsize{\@setfontsize{\scriptsize}{8}{9pt}} +\def\tiny{\@setfontsize{\tiny}{6}{7pt}} +% sublargesize is the same as large - 14pt +\def\sublargesize{\@setfontsize{\sublargesize}{14}{17pt}} +\def\large{\@setfontsize{\large}{14}{17pt}} +\def\Large{\@setfontsize{\Large}{17}{20pt}} +\def\LARGE{\@setfontsize{\LARGE}{20}{24pt}} +\def\huge{\@setfontsize{\huge}{22}{26pt}} +\def\Huge{\@setfontsize{\Huge}{24}{28pt}} +\fi + + +% V1.6 The Computer Modern Fonts will issue a substitution warning for +% 24pt titles (24.88pt is used instead) increase the substitution +% tolerance to turn off this warning +\def\fontsubfuzz{.9pt} +% However, the default (and correct) Times font will scale exactly as needed. + + +% warn the user in case they forget to use the 9pt option with +% technote +\ifCLASSOPTIONtechnote% + \ifx\CLASSOPTIONpt\@IEEEptsizenine\else% + \typeout{** ATTENTION: Technotes are normally 9pt documents.}% + \fi% +\fi + + +% V1.7 +% Improved \textunderscore to provide a much better fake _ when used with +% OT1 encoding. Under OT1, detect use of pcr or cmtt \ttfamily and use +% available true _ glyph for those two typewriter fonts. +\def\@IEEEstringptm{ptm} % Times Roman family +\def\@IEEEstringppl{ppl} % Palatino Roman family +\def\@IEEEstringphv{phv} % Helvetica Sans Serif family +\def\@IEEEstringpcr{pcr} % Courier typewriter family +\def\@IEEEstringcmtt{cmtt} % Computer Modern typewriter family +\DeclareTextCommandDefault{\textunderscore}{\leavevmode +\ifx\f@family\@IEEEstringpcr\string_\else +\ifx\f@family\@IEEEstringcmtt\string_\else +\ifx\f@family\@IEEEstringptm\kern 0em\vbox{\hrule\@width 0.5em\@height 0.5pt\kern -0.3ex}\else +\ifx\f@family\@IEEEstringppl\kern 0em\vbox{\hrule\@width 0.5em\@height 0.5pt\kern -0.3ex}\else +\ifx\f@family\@IEEEstringphv\kern -0.03em\vbox{\hrule\@width 0.62em\@height 0.52pt\kern -0.33ex}\kern -0.03em\else +\kern 0.09em\vbox{\hrule\@width 0.6em\@height 0.44pt\kern -0.63pt\kern -0.42ex}\kern 0.09em\fi\fi\fi\fi\fi\relax} + + + + +% set the default \baselinestretch +\def\baselinestretch{1} +\ifCLASSOPTIONdraftcls + \def\baselinestretch{1.5}% default baselinestretch for draft modes +\fi + + +% process CLASSINPUT baselinestretch +\ifx\CLASSINPUTbaselinestretch\@IEEEundefined +\else + \edef\baselinestretch{\CLASSINPUTbaselinestretch} % user CLASSINPUT override + \typeout{** ATTENTION: Overriding \string\baselinestretch\space to + \baselinestretch\space via \string\CLASSINPUT.} +\fi + +\normalsize % make \baselinestretch take affect + + + + +% store the normalsize baselineskip +\newdimen\CLASSINFOnormalsizebaselineskip +\CLASSINFOnormalsizebaselineskip=\baselineskip\relax +% and the normalsize unity (baselinestretch=1) baselineskip +% we could save a register by giving the user access to +% \@IEEEnormalsizeunitybaselineskip. However, let's protect +% its read only internal status +\newdimen\CLASSINFOnormalsizeunitybaselineskip +\CLASSINFOnormalsizeunitybaselineskip=\@IEEEnormalsizeunitybaselineskip\relax +% store the nominal value of jot +\newdimen\IEEEnormaljot +\IEEEnormaljot=0.25\baselineskip\relax + +% set \jot +\jot=\IEEEnormaljot\relax + + + + +% V1.6, we are now going to fine tune the interword spacing +% The default interword glue for Times under TeX appears to use a +% nominal interword spacing of 25% (relative to the font size, i.e., 1em) +% a maximum of 40% and a minimum of 19%. +% For example, 10pt text uses an interword glue of: +% +% 2.5pt plus 1.49998pt minus 0.59998pt +% +% However, IEEE allows for a more generous range which reduces the need +% for hyphenation, especially for two column text. Furthermore, IEEE +% tends to use a little bit more nominal space between the words. +% IEEE's interword spacing percentages appear to be: +% 35% nominal +% 23% minimum +% 50% maximum +% (They may even be using a tad more for the largest fonts such as 24pt.) +% +% for bold text, IEEE increases the spacing a little more: +% 37.5% nominal +% 23% minimum +% 55% maximum + +% here are the interword spacing ratios we'll use +% for medium (normal weight) +\def\@IEEEinterspaceratioM{0.35} +\def\@IEEEinterspaceMINratioM{0.23} +\def\@IEEEinterspaceMAXratioM{0.50} + +% for bold +\def\@IEEEinterspaceratioB{0.375} +\def\@IEEEinterspaceMINratioB{0.23} +\def\@IEEEinterspaceMAXratioB{0.55} + + +% command to revise the interword spacing for the current font under TeX: +% \fontdimen2 = nominal interword space +% \fontdimen3 = interword stretch +% \fontdimen4 = interword shrink +% since all changes to the \fontdimen are global, we can enclose these commands +% in braces to confine any font attribute or length changes +\def\@@@IEEEsetfontdimens#1#2#3{{% +\setlength{\@IEEEtrantmpdimenB}{\f@size pt}% grab the font size in pt, could use 1em instead. +\setlength{\@IEEEtrantmpdimenA}{#1\@IEEEtrantmpdimenB}% +\fontdimen2\font=\@IEEEtrantmpdimenA\relax +\addtolength{\@IEEEtrantmpdimenA}{-#2\@IEEEtrantmpdimenB}% +\fontdimen3\font=-\@IEEEtrantmpdimenA\relax +\setlength{\@IEEEtrantmpdimenA}{#1\@IEEEtrantmpdimenB}% +\addtolength{\@IEEEtrantmpdimenA}{-#3\@IEEEtrantmpdimenB}% +\fontdimen4\font=\@IEEEtrantmpdimenA\relax}} + +% revise the interword spacing for each font weight +\def\@@IEEEsetfontdimens{{% +\mdseries +\@@@IEEEsetfontdimens{\@IEEEinterspaceratioM}{\@IEEEinterspaceMAXratioM}{\@IEEEinterspaceMINratioM}% +\bfseries +\@@@IEEEsetfontdimens{\@IEEEinterspaceratioB}{\@IEEEinterspaceMAXratioB}{\@IEEEinterspaceMINratioB}% +}} + +% revise the interword spacing for each font shape +% \slshape is not often used for IEEE work and is not altered here. The \scshape caps are +% already a tad too large in the free LaTeX fonts (as compared to what IEEE uses) so we +% won't alter these either. +\def\@IEEEsetfontdimens{{% +\normalfont +\@@IEEEsetfontdimens +\normalfont\itshape +\@@IEEEsetfontdimens +}} + +% command to revise the interword spacing for each font size (and shape +% and weight). Only the \rmfamily is done here as \ttfamily uses a +% fixed spacing and \sffamily is not used as the main text of IEEE papers. +\def\@IEEEtunefonts{{\selectfont\rmfamily +\tiny\@IEEEsetfontdimens +\scriptsize\@IEEEsetfontdimens +\footnotesize\@IEEEsetfontdimens +\small\@IEEEsetfontdimens +\normalsize\@IEEEsetfontdimens +\sublargesize\@IEEEsetfontdimens +\large\@IEEEsetfontdimens +\LARGE\@IEEEsetfontdimens +\huge\@IEEEsetfontdimens +\Huge\@IEEEsetfontdimens}} + +% if the nofonttune class option is not given, revise the interword spacing +% now - in case IEEEtran makes any default length measurements, and make +% sure all the default fonts are loaded +\ifCLASSOPTIONnofonttune\else +\@IEEEtunefonts +\fi + +% and again at the start of the document in case the user loaded different fonts +\AtBeginDocument{\ifCLASSOPTIONnofonttune\else\@IEEEtunefonts\fi} + + + +% V1.6 +% LaTeX is a little to quick to use hyphenations +% So, we increase the penalty for their use and raise +% the badness level that triggers an underfull hbox +% warning. The author may still have to tweak things, +% but the appearance will be much better "right out +% of the box" than that under V1.5 and prior. +% TeX default is 50 +\hyphenpenalty=750 +% If we didn't adjust the interword spacing, 2200 might be better. +% The TeX default is 1000 +\hbadness=1350 +% IEEE does not use extra spacing after punctuation +\frenchspacing + +% V1.7 increase this a tad to discourage equation breaks +\binoppenalty=1000 % default 700 +\relpenalty=800 % default 500 + + +% margin note stuff +\marginparsep 10pt +\marginparwidth 20pt +\marginparpush 25pt + + +% if things get too close, go ahead and let them touch +\lineskip 0pt +\normallineskip 0pt +\lineskiplimit 0pt +\normallineskiplimit 0pt + +% The distance from the lower edge of the text body to the +% footline +\footskip 0.4in + +% normally zero, should be relative to font height. +% put in a little rubber to help stop some bad breaks (underfull vboxes) +\parskip 0ex plus 0.2ex minus 0.1ex + +\parindent 1.0em + +\topmargin -49.0pt +\headheight 12pt +\headsep 0.25in + +% use the normal font baselineskip +% so that \topskip is unaffected by changes in \baselinestretch +\topskip=\@IEEEnormalsizeunitybaselineskip +\textheight 58pc % 9.63in, 696pt +% Tweak textheight to a perfect integer number of lines/page. +% The normal baselineskip for each document point size is used +% to determine these values. +\ifx\CLASSOPTIONpt\@IEEEptsizenine\textheight=63\@IEEEnormalsizeunitybaselineskip\fi % 63 lines/page +\ifx\CLASSOPTIONpt\@IEEEptsizeten\textheight=58\@IEEEnormalsizeunitybaselineskip\fi % 58 lines/page +\ifx\CLASSOPTIONpt\@IEEEptsizeeleven\textheight=52\@IEEEnormalsizeunitybaselineskip\fi % 52 lines/page +\ifx\CLASSOPTIONpt\@IEEEptsizetwelve\textheight=50\@IEEEnormalsizeunitybaselineskip\fi % 50 lines/page + + +\columnsep 1pc +\textwidth 43pc % 2 x 21pc + 1pc = 43pc + + +% the default side margins are equal +\if@IEEEusingAfourpaper +\oddsidemargin 14.32mm +\evensidemargin 14.32mm +\else +\oddsidemargin 0.680in +\evensidemargin 0.680in +\fi +% compensate for LaTeX's 1in offset +\addtolength{\oddsidemargin}{-1in} +\addtolength{\evensidemargin}{-1in} + + + +% adjust margins for conference mode +\ifCLASSOPTIONconference + \topmargin -0.25in + % we retain the reserved, but unused space for headers + \addtolength{\topmargin}{-\headheight} + \addtolength{\topmargin}{-\headsep} + \textheight 9.25in % The standard for conferences (668.4975pt) + % Tweak textheight to a perfect integer number of lines/page. + \ifx\CLASSOPTIONpt\@IEEEptsizenine\textheight=61\@IEEEnormalsizeunitybaselineskip\fi % 61 lines/page + \ifx\CLASSOPTIONpt\@IEEEptsizeten\textheight=56\@IEEEnormalsizeunitybaselineskip\fi % 56 lines/page + \ifx\CLASSOPTIONpt\@IEEEptsizeeleven\textheight=50\@IEEEnormalsizeunitybaselineskip\fi % 50 lines/page + \ifx\CLASSOPTIONpt\@IEEEptsizetwelve\textheight=48\@IEEEnormalsizeunitybaselineskip\fi % 48 lines/page +\fi + + +% compsoc conference +\ifCLASSOPTIONcompsoc +\ifCLASSOPTIONconference + % compsoc conference use a larger value for columnsep + \columnsep 0.375in + % compsoc conferences want 1in top margin, 1.125in bottom margin + \topmargin 0in + \addtolength{\topmargin}{-6pt}% we tweak this a tad to better comply with top of line stuff + % we retain the reserved, but unused space for headers + \addtolength{\topmargin}{-\headheight} + \addtolength{\topmargin}{-\headsep} + \textheight 8.875in % (641.39625pt) + % Tweak textheight to a perfect integer number of lines/page. + \ifx\CLASSOPTIONpt\@IEEEptsizenine\textheight=58\@IEEEnormalsizeunitybaselineskip\fi % 58 lines/page + \ifx\CLASSOPTIONpt\@IEEEptsizeten\textheight=53\@IEEEnormalsizeunitybaselineskip\fi % 53 lines/page + \ifx\CLASSOPTIONpt\@IEEEptsizeeleven\textheight=48\@IEEEnormalsizeunitybaselineskip\fi % 48 lines/page + \ifx\CLASSOPTIONpt\@IEEEptsizetwelve\textheight=46\@IEEEnormalsizeunitybaselineskip\fi % 46 lines/page + \textwidth 6.5in + % the default side margins are equal + \if@IEEEusingAfourpaper + \oddsidemargin 22.45mm + \evensidemargin 22.45mm + \else + \oddsidemargin 1in + \evensidemargin 1in + \fi + % compensate for LaTeX's 1in offset + \addtolength{\oddsidemargin}{-1in} + \addtolength{\evensidemargin}{-1in} +\fi\fi + + + +% draft mode settings override that of all other modes +% provides a nice 1in margin all around the paper and extra +% space between the lines for editor's comments +\ifCLASSOPTIONdraftcls + % want 1in from top of paper to text + \setlength{\topmargin}{-\headsep}% + \addtolength{\topmargin}{-\headheight}% + % we want 1in side margins regardless of paper type + \oddsidemargin 0in + \evensidemargin 0in + % set the text width + \setlength{\textwidth}{\paperwidth}% + \addtolength{\textwidth}{-2.0in}% + \setlength{\textheight}{\paperheight}% + \addtolength{\textheight}{-2.0in}% + % digitize textheight to be an integer number of lines. + % this may cause the bottom margin to be off a tad + \addtolength{\textheight}{-1\topskip}% + \divide\textheight by \baselineskip% + \multiply\textheight by \baselineskip% + \addtolength{\textheight}{\topskip}% +\fi + + + +% process CLASSINPUT inner/outer margin +% if inner margin defined, but outer margin not, set outer to inner. +\ifx\CLASSINPUTinnersidemargin\@IEEEundefined +\else + \ifx\CLASSINPUToutersidemargin\@IEEEundefined + \edef\CLASSINPUToutersidemargin{\CLASSINPUTinnersidemargin} + \fi +\fi + +\ifx\CLASSINPUToutersidemargin\@IEEEundefined +\else + % if outer margin defined, but inner margin not, set inner to outer. + \ifx\CLASSINPUTinnersidemargin\@IEEEundefined + \edef\CLASSINPUTinnersidemargin{\CLASSINPUToutersidemargin} + \fi + \setlength{\oddsidemargin}{\CLASSINPUTinnersidemargin} + \ifCLASSOPTIONtwoside + \setlength{\evensidemargin}{\CLASSINPUToutersidemargin} + \else + \setlength{\evensidemargin}{\CLASSINPUTinnersidemargin} + \fi + \addtolength{\oddsidemargin}{-1in} + \addtolength{\evensidemargin}{-1in} + \setlength{\textwidth}{\paperwidth} + \addtolength{\textwidth}{-\CLASSINPUTinnersidemargin} + \addtolength{\textwidth}{-\CLASSINPUToutersidemargin} + \typeout{** ATTENTION: Overriding inner side margin to \CLASSINPUTinnersidemargin\space and + outer side margin to \CLASSINPUToutersidemargin\space via \string\CLASSINPUT.} +\fi + + + +% process CLASSINPUT top/bottom text margin +% if toptext margin defined, but bottomtext margin not, set bottomtext to toptext margin +\ifx\CLASSINPUTtoptextmargin\@IEEEundefined +\else + \ifx\CLASSINPUTbottomtextmargin\@IEEEundefined + \edef\CLASSINPUTbottomtextmargin{\CLASSINPUTtoptextmargin} + \fi +\fi + +\ifx\CLASSINPUTbottomtextmargin\@IEEEundefined +\else + % if bottomtext margin defined, but toptext margin not, set toptext to bottomtext margin + \ifx\CLASSINPUTtoptextmargin\@IEEEundefined + \edef\CLASSINPUTtoptextmargin{\CLASSINPUTbottomtextmargin} + \fi + \setlength{\topmargin}{\CLASSINPUTtoptextmargin} + \addtolength{\topmargin}{-1in} + \addtolength{\topmargin}{-\headheight} + \addtolength{\topmargin}{-\headsep} + \setlength{\textheight}{\paperheight} + \addtolength{\textheight}{-\CLASSINPUTtoptextmargin} + \addtolength{\textheight}{-\CLASSINPUTbottomtextmargin} + % in the default format we use the normal baselineskip as topskip + % we only need 0.7 of this to clear typical top text and we need + % an extra 0.3 spacing at the bottom for descenders. This will + % correct for both. + \addtolength{\topmargin}{-0.3\@IEEEnormalsizeunitybaselineskip} + \typeout{** ATTENTION: Overriding top text margin to \CLASSINPUTtoptextmargin\space and + bottom text margin to \CLASSINPUTbottomtextmargin\space via \string\CLASSINPUT.} +\fi + + + + + + + +% LIST SPACING CONTROLS + +% Controls the amount of EXTRA spacing +% above and below \trivlist +% Both \list and IED lists override this. +% However, \trivlist will use this as will most +% things built from \trivlist like the \center +% environment. +\topsep 0.5\baselineskip + +% Controls the additional spacing around lists preceded +% or followed by blank lines. IEEE does not increase +% spacing before or after paragraphs so it is set to zero. +% \z@ is the same as zero, but faster. +\partopsep \z@ + +% Controls the spacing between paragraphs in lists. +% IEEE does not increase spacing before or after paragraphs +% so this is also zero. +% With IEEEtran.cls, global changes to +% this value DO affect lists (but not IED lists). +\parsep \z@ + +% Controls the extra spacing between list items. +% IEEE does not put extra spacing between items. +% With IEEEtran.cls, global changes to this value DO affect +% lists (but not IED lists). +\itemsep \z@ + +% \itemindent is the amount to indent the FIRST line of a list +% item. It is auto set to zero within the \list environment. To alter +% it, you have to do so when you call the \list. +% However, IEEE uses this for the theorem environment +% There is an alternative value for this near \leftmargini below +\itemindent -1em + +% \leftmargin, the spacing from the left margin of the main text to +% the left of the main body of a list item is set by \list. +% Hence this statement does nothing for lists. +% But, quote and verse do use it for indention. +\leftmargin 2em + +% we retain this stuff from the older IEEEtran.cls so that \list +% will work the same way as before. However, itemize, enumerate and +% description (IED) could care less about what these are as they +% all are overridden. +\leftmargini 2em +%\itemindent 2em % Alternative values: sometimes used. +%\leftmargini 0em +\leftmarginii 1em +\leftmarginiii 1.5em +\leftmarginiv 1.5em +\leftmarginv 1.0em +\leftmarginvi 1.0em +\labelsep 0.5em +\labelwidth \z@ + + +% The old IEEEtran.cls behavior of \list is retained. +% However, the new V1.3 IED list environments override all the +% @list stuff (\@listX is called within \list for the +% appropriate level just before the user's list_decl is called). +% \topsep is now 2pt as IEEE puts a little extra space around +% lists - used by those non-IED macros that depend on \list. +% Note that \parsep and \itemsep are not redefined as in +% the sizexx.clo \@listX (which article.cls uses) so global changes +% of these values DO affect \list +% +\def\@listi{\leftmargin\leftmargini \topsep 2pt plus 1pt minus 1pt} +\let\@listI\@listi +\def\@listii{\leftmargin\leftmarginii\labelwidth\leftmarginii% + \advance\labelwidth-\labelsep \topsep 2pt} +\def\@listiii{\leftmargin\leftmarginiii\labelwidth\leftmarginiii% + \advance\labelwidth-\labelsep \topsep 2pt} +\def\@listiv{\leftmargin\leftmarginiv\labelwidth\leftmarginiv% + \advance\labelwidth-\labelsep \topsep 2pt} +\def\@listv{\leftmargin\leftmarginv\labelwidth\leftmarginv% + \advance\labelwidth-\labelsep \topsep 2pt} +\def\@listvi{\leftmargin\leftmarginvi\labelwidth\leftmarginvi% + \advance\labelwidth-\labelsep \topsep 2pt} + + +% IEEE uses 5) not 5. +\def\labelenumi{\theenumi)} \def\theenumi{\arabic{enumi}} + +% IEEE uses a) not (a) +\def\labelenumii{\theenumii)} \def\theenumii{\alph{enumii}} + +% IEEE uses iii) not iii. +\def\labelenumiii{\theenumiii)} \def\theenumiii{\roman{enumiii}} + +% IEEE uses A) not A. +\def\labelenumiv{\theenumiv)} \def\theenumiv{\Alph{enumiv}} + +% exactly the same as in article.cls +\def\p@enumii{\theenumi} +\def\p@enumiii{\theenumi(\theenumii)} +\def\p@enumiv{\p@enumiii\theenumiii} + +% itemized list label styles +\def\labelitemi{$\scriptstyle\bullet$} +\def\labelitemii{\textbf{--}} +\def\labelitemiii{$\ast$} +\def\labelitemiv{$\cdot$} + + + +% **** V1.3 ENHANCEMENTS **** +% Itemize, Enumerate and Description (IED) List Controls +% *************************** +% +% +% IEEE seems to use at least two different values by +% which ITEMIZED list labels are indented to the right +% For The Journal of Lightwave Technology (JLT) and The Journal +% on Selected Areas in Communications (JSAC), they tend to use +% an indention equal to \parindent. For Transactions on Communications +% they tend to indent ITEMIZED lists a little more--- 1.3\parindent. +% We'll provide both values here for you so that you can choose +% which one you like in your document using a command such as: +% setlength{\IEEEilabelindent}{\IEEEilabelindentB} +\newdimen\IEEEilabelindentA +\IEEEilabelindentA \parindent + +\newdimen\IEEEilabelindentB +\IEEEilabelindentB 1.3\parindent +% However, we'll default to using \parindent +% which makes more sense to me +\newdimen\IEEEilabelindent +\IEEEilabelindent \IEEEilabelindentA + + +% This controls the default amount the enumerated list labels +% are indented to the right. +% Normally, this is the same as the paragraph indention +\newdimen\IEEEelabelindent +\IEEEelabelindent \parindent + +% This controls the default amount the description list labels +% are indented to the right. +% Normally, this is the same as the paragraph indention +\newdimen\IEEEdlabelindent +\IEEEdlabelindent \parindent + +% This is the value actually used within the IED lists. +% The IED environments automatically set its value to +% one of the three values above, so global changes do +% not have any effect +\newdimen\IEEElabelindent +\IEEElabelindent \parindent + +% The actual amount labels will be indented is +% \IEEElabelindent multiplied by the factor below +% corresponding to the level of nesting depth +% This provides a means by which the user can +% alter the effective \IEEElabelindent for deeper +% levels +% There may not be such a thing as correct "standard IEEE" +% values. What IEEE actually does may depend on the specific +% circumstances. +% The first list level almost always has full indention. +% The second levels I've seen have only 75% of the normal indentation +% Three level or greater nestings are very rare. I am guessing +% that they don't use any indentation. +\def\IEEElabelindentfactori{1.0} % almost always one +\def\IEEElabelindentfactorii{0.75} % 0.0 or 1.0 may be used in some cases +\def\IEEElabelindentfactoriii{0.0} % 0.75? 0.5? 0.0? +\def\IEEElabelindentfactoriv{0.0} +\def\IEEElabelindentfactorv{0.0} +\def\IEEElabelindentfactorvi{0.0} + +% value actually used within IED lists, it is auto +% set to one of the 6 values above +% global changes here have no effect +\def\IEEElabelindentfactor{1.0} + +% This controls the default spacing between the end of the IED +% list labels and the list text, when normal text is used for +% the labels. +\newdimen\IEEEiednormlabelsep +\IEEEiednormlabelsep 0.6em + +% This controls the default spacing between the end of the IED +% list labels and the list text, when math symbols are used for +% the labels (nomenclature lists). IEEE usually increases the +% spacing in these cases +\newdimen\IEEEiedmathlabelsep +\IEEEiedmathlabelsep 1.2em + +% This controls the extra vertical separation put above and +% below each IED list. IEEE usually puts a little extra spacing +% around each list. However, this spacing is barely noticeable. +\newskip\IEEEiedtopsep +\IEEEiedtopsep 2pt plus 1pt minus 1pt + + +% This command is executed within each IED list environment +% at the beginning of the list. You can use this to set the +% parameters for some/all your IED list(s) without disturbing +% global parameters that affect things other than lists. +% i.e., renewcommand{\IEEEiedlistdecl}{\setlength{\labelsep}{5em}} +% will alter the \labelsep for the next list(s) until +% \IEEEiedlistdecl is redefined. +\def\IEEEiedlistdecl{\relax} + +% This command provides an easy way to set \leftmargin based +% on the \labelwidth, \labelsep and the argument \IEEElabelindent +% Usage: \IEEEcalcleftmargin{width-to-indent-the-label} +% output is in the \leftmargin variable, i.e., effectively: +% \leftmargin = argument + \labelwidth + \labelsep +% Note controlled spacing here, shield end of lines with % +\def\IEEEcalcleftmargin#1{\setlength{\leftmargin}{#1}% +\addtolength{\leftmargin}{\labelwidth}% +\addtolength{\leftmargin}{\labelsep}} + +% This command provides an easy way to set \labelwidth to the +% width of the given text. It is the same as +% \settowidth{\labelwidth}{label-text} +% and useful as a shorter alternative. +% Typically used to set \labelwidth to be the width +% of the longest label in the list +\def\IEEEsetlabelwidth#1{\settowidth{\labelwidth}{#1}} + +% When this command is executed, IED lists will use the +% IEEEiedmathlabelsep label separation rather than the normal +% spacing. To have an effect, this command must be executed via +% the \IEEEiedlistdecl or within the option of the IED list +% environments. +\def\IEEEusemathlabelsep{\setlength{\labelsep}{\IEEEiedmathlabelsep}} + +% A flag which controls whether the IED lists automatically +% calculate \leftmargin from \IEEElabelindent, \labelwidth and \labelsep +% Useful if you want to specify your own \leftmargin +% This flag must be set (\IEEEnocalcleftmargintrue or \IEEEnocalcleftmarginfalse) +% via the \IEEEiedlistdecl or within the option of the IED list +% environments to have an effect. +\newif\ifIEEEnocalcleftmargin +\IEEEnocalcleftmarginfalse + +% A flag which controls whether \IEEElabelindent is multiplied by +% the \IEEElabelindentfactor for each list level. +% This flag must be set via the \IEEEiedlistdecl or within the option +% of the IED list environments to have an effect. +\newif\ifIEEEnolabelindentfactor +\IEEEnolabelindentfactorfalse + + +% internal variable to indicate type of IED label +% justification +% 0 - left; 1 - center; 2 - right +\def\@IEEEiedjustify{0} + + +% commands to allow the user to control IED +% label justifications. Use these commands within +% the IED environment option or in the \IEEEiedlistdecl +% Note that changing the normal list justifications +% is nonstandard and IEEE may not like it if you do so! +% I include these commands as they may be helpful to +% those who are using these enhanced list controls for +% other non-IEEE related LaTeX work. +% itemize and enumerate automatically default to right +% justification, description defaults to left. +\def\IEEEiedlabeljustifyl{\def\@IEEEiedjustify{0}}%left +\def\IEEEiedlabeljustifyc{\def\@IEEEiedjustify{1}}%center +\def\IEEEiedlabeljustifyr{\def\@IEEEiedjustify{2}}%right + + + + +% commands to save to and restore from the list parameter copies +% this allows us to set all the list parameters within +% the list_decl and prevent \list (and its \@list) +% from overriding any of our parameters +% V1.6 use \edefs instead of dimen's to conserve dimen registers +% Note controlled spacing here, shield end of lines with % +\def\@IEEEsavelistparams{\edef\@IEEEiedtopsep{\the\topsep}% +\edef\@IEEEiedlabelwidth{\the\labelwidth}% +\edef\@IEEEiedlabelsep{\the\labelsep}% +\edef\@IEEEiedleftmargin{\the\leftmargin}% +\edef\@IEEEiedpartopsep{\the\partopsep}% +\edef\@IEEEiedparsep{\the\parsep}% +\edef\@IEEEieditemsep{\the\itemsep}% +\edef\@IEEEiedrightmargin{\the\rightmargin}% +\edef\@IEEEiedlistparindent{\the\listparindent}% +\edef\@IEEEieditemindent{\the\itemindent}} + +% Note controlled spacing here +\def\@IEEErestorelistparams{\topsep\@IEEEiedtopsep\relax% +\labelwidth\@IEEEiedlabelwidth\relax% +\labelsep\@IEEEiedlabelsep\relax% +\leftmargin\@IEEEiedleftmargin\relax% +\partopsep\@IEEEiedpartopsep\relax% +\parsep\@IEEEiedparsep\relax% +\itemsep\@IEEEieditemsep\relax% +\rightmargin\@IEEEiedrightmargin\relax% +\listparindent\@IEEEiedlistparindent\relax% +\itemindent\@IEEEieditemindent\relax} + + +% v1.6b provide original LaTeX IED list environments +% note that latex.ltx defines \itemize and \enumerate, but not \description +% which must be created by the base classes +% save original LaTeX itemize and enumerate +\let\LaTeXitemize\itemize +\let\endLaTeXitemize\enditemize +\let\LaTeXenumerate\enumerate +\let\endLaTeXenumerate\endenumerate + +% provide original LaTeX description environment from article.cls +\newenvironment{LaTeXdescription} + {\list{}{\labelwidth\z@ \itemindent-\leftmargin + \let\makelabel\descriptionlabel}} + {\endlist} +\newcommand*\descriptionlabel[1]{\hspace\labelsep + \normalfont\bfseries #1} + + +% override LaTeX's default IED lists +\def\itemize{\@IEEEitemize} +\def\enditemize{\@endIEEEitemize} +\def\enumerate{\@IEEEenumerate} +\def\endenumerate{\@endIEEEenumerate} +\def\description{\@IEEEdescription} +\def\enddescription{\@endIEEEdescription} + +% provide the user with aliases - may help those using packages that +% override itemize, enumerate, or description +\def\IEEEitemize{\@IEEEitemize} +\def\endIEEEitemize{\@endIEEEitemize} +\def\IEEEenumerate{\@IEEEenumerate} +\def\endIEEEenumerate{\@endIEEEenumerate} +\def\IEEEdescription{\@IEEEdescription} +\def\endIEEEdescription{\@endIEEEdescription} + + +% V1.6 we want to keep the IEEEtran IED list definitions as our own internal +% commands so they are protected against redefinition +\def\@IEEEitemize{\@ifnextchar[{\@@IEEEitemize}{\@@IEEEitemize[\relax]}} +\def\@IEEEenumerate{\@ifnextchar[{\@@IEEEenumerate}{\@@IEEEenumerate[\relax]}} +\def\@IEEEdescription{\@ifnextchar[{\@@IEEEdescription}{\@@IEEEdescription[\relax]}} +\def\@endIEEEitemize{\endlist} +\def\@endIEEEenumerate{\endlist} +\def\@endIEEEdescription{\endlist} + + +% DO NOT ALLOW BLANK LINES TO BE IN THESE IED ENVIRONMENTS +% AS THIS WILL FORCE NEW PARAGRAPHS AFTER THE IED LISTS +% IEEEtran itemized list MDS 1/2001 +% Note controlled spacing here, shield end of lines with % +\def\@@IEEEitemize[#1]{% + \ifnum\@itemdepth>3\relax\@toodeep\else% + \ifnum\@listdepth>5\relax\@toodeep\else% + \advance\@itemdepth\@ne% + \edef\@itemitem{labelitem\romannumeral\the\@itemdepth}% + % get the labelindentfactor for this level + \advance\@listdepth\@ne% we need to know what the level WILL be + \edef\IEEElabelindentfactor{\csname IEEElabelindentfactor\romannumeral\the\@listdepth\endcsname}% + \advance\@listdepth-\@ne% undo our increment + \def\@IEEEiedjustify{2}% right justified labels are default + % set other defaults + \IEEEnocalcleftmarginfalse% + \IEEEnolabelindentfactorfalse% + \topsep\IEEEiedtopsep% + \IEEElabelindent\IEEEilabelindent% + \labelsep\IEEEiednormlabelsep% + \partopsep 0ex% + \parsep 0ex% + \itemsep 0ex% + \rightmargin 0em% + \listparindent 0em% + \itemindent 0em% + % calculate the label width + % the user can override this later if + % they specified a \labelwidth + \settowidth{\labelwidth}{\csname labelitem\romannumeral\the\@itemdepth\endcsname}% + \@IEEEsavelistparams% save our list parameters + \list{\csname\@itemitem\endcsname}{% + \@IEEErestorelistparams% override any list{} changes + % to our globals + \let\makelabel\@IEEEiedmakelabel% v1.6b setup \makelabel + \IEEEiedlistdecl% let user alter parameters + #1\relax% + % If the user has requested not to use the + % labelindent factor, don't revise \labelindent + \ifIEEEnolabelindentfactor\relax% + \else\IEEElabelindent=\IEEElabelindentfactor\labelindent% + \fi% + % Unless the user has requested otherwise, + % calculate our left margin based + % on \IEEElabelindent, \labelwidth and + % \labelsep + \ifIEEEnocalcleftmargin\relax% + \else\IEEEcalcleftmargin{\IEEElabelindent}% + \fi}\fi\fi}% + + +% DO NOT ALLOW BLANK LINES TO BE IN THESE IED ENVIRONMENTS +% AS THIS WILL FORCE NEW PARAGRAPHS AFTER THE IED LISTS +% IEEEtran enumerate list MDS 1/2001 +% Note controlled spacing here, shield end of lines with % +\def\@@IEEEenumerate[#1]{% + \ifnum\@enumdepth>3\relax\@toodeep\else% + \ifnum\@listdepth>5\relax\@toodeep\else% + \advance\@enumdepth\@ne% + \edef\@enumctr{enum\romannumeral\the\@enumdepth}% + % get the labelindentfactor for this level + \advance\@listdepth\@ne% we need to know what the level WILL be + \edef\IEEElabelindentfactor{\csname IEEElabelindentfactor\romannumeral\the\@listdepth\endcsname}% + \advance\@listdepth-\@ne% undo our increment + \def\@IEEEiedjustify{2}% right justified labels are default + % set other defaults + \IEEEnocalcleftmarginfalse% + \IEEEnolabelindentfactorfalse% + \topsep\IEEEiedtopsep% + \IEEElabelindent\IEEEelabelindent% + \labelsep\IEEEiednormlabelsep% + \partopsep 0ex% + \parsep 0ex% + \itemsep 0ex% + \rightmargin 0em% + \listparindent 0em% + \itemindent 0em% + % calculate the label width + % We'll set it to the width suitable for all labels using + % normalfont 1) to 9) + % The user can override this later + \settowidth{\labelwidth}{9)}% + \@IEEEsavelistparams% save our list parameters + \list{\csname label\@enumctr\endcsname}{\usecounter{\@enumctr}% + \@IEEErestorelistparams% override any list{} changes + % to our globals + \let\makelabel\@IEEEiedmakelabel% v1.6b setup \makelabel + \IEEEiedlistdecl% let user alter parameters + #1\relax% + % If the user has requested not to use the + % IEEElabelindent factor, don't revise \IEEElabelindent + \ifIEEEnolabelindentfactor\relax% + \else\IEEElabelindent=\IEEElabelindentfactor\IEEElabelindent% + \fi% + % Unless the user has requested otherwise, + % calculate our left margin based + % on \IEEElabelindent, \labelwidth and + % \labelsep + \ifIEEEnocalcleftmargin\relax% + \else\IEEEcalcleftmargin{\IEEElabelindent}% + \fi}\fi\fi}% + + +% DO NOT ALLOW BLANK LINES TO BE IN THESE IED ENVIRONMENTS +% AS THIS WILL FORCE NEW PARAGRAPHS AFTER THE IED LISTS +% IEEEtran description list MDS 1/2001 +% Note controlled spacing here, shield end of lines with % +\def\@@IEEEdescription[#1]{% + \ifnum\@listdepth>5\relax\@toodeep\else% + % get the labelindentfactor for this level + \advance\@listdepth\@ne% we need to know what the level WILL be + \edef\IEEElabelindentfactor{\csname IEEElabelindentfactor\romannumeral\the\@listdepth\endcsname}% + \advance\@listdepth-\@ne% undo our increment + \def\@IEEEiedjustify{0}% left justified labels are default + % set other defaults + \IEEEnocalcleftmarginfalse% + \IEEEnolabelindentfactorfalse% + \topsep\IEEEiedtopsep% + \IEEElabelindent\IEEEdlabelindent% + % assume normal labelsep + \labelsep\IEEEiednormlabelsep% + \partopsep 0ex% + \parsep 0ex% + \itemsep 0ex% + \rightmargin 0em% + \listparindent 0em% + \itemindent 0em% + % Bogus label width in case the user forgets + % to set it. + % TIP: If you want to see what a variable's width is you + % can use the TeX command \showthe\width-variable to + % display it on the screen during compilation + % (This might be helpful to know when you need to find out + % which label is the widest) + \settowidth{\labelwidth}{Hello}% + \@IEEEsavelistparams% save our list parameters + \list{}{\@IEEErestorelistparams% override any list{} changes + % to our globals + \let\makelabel\@IEEEiedmakelabel% v1.6b setup \makelabel + \IEEEiedlistdecl% let user alter parameters + #1\relax% + % If the user has requested not to use the + % labelindent factor, don't revise \IEEElabelindent + \ifIEEEnolabelindentfactor\relax% + \else\IEEElabelindent=\IEEElabelindentfactor\IEEElabelindent% + \fi% + % Unless the user has requested otherwise, + % calculate our left margin based + % on \IEEElabelindent, \labelwidth and + % \labelsep + \ifIEEEnocalcleftmargin\relax% + \else\IEEEcalcleftmargin{\IEEElabelindent}\relax% + \fi}\fi} + +% v1.6b we use one makelabel that does justification as needed. +\def\@IEEEiedmakelabel#1{\relax\if\@IEEEiedjustify 0\relax +\makebox[\labelwidth][l]{\normalfont #1}\else +\if\@IEEEiedjustify 1\relax +\makebox[\labelwidth][c]{\normalfont #1}\else +\makebox[\labelwidth][r]{\normalfont #1}\fi\fi} + + +% VERSE and QUOTE +% V1.7 define environments with newenvironment +\newenvironment{verse}{\let\\=\@centercr + \list{}{\itemsep\z@ \itemindent -1.5em \listparindent \itemindent + \rightmargin\leftmargin\advance\leftmargin 1.5em}\item\relax} + {\endlist} +\newenvironment{quotation}{\list{}{\listparindent 1.5em \itemindent\listparindent + \rightmargin\leftmargin \parsep 0pt plus 1pt}\item\relax} + {\endlist} +\newenvironment{quote}{\list{}{\rightmargin\leftmargin}\item\relax} + {\endlist} + + +% \titlepage +% provided only for backward compatibility. \maketitle is the correct +% way to create the title page. +\newif\if@restonecol +\def\titlepage{\@restonecolfalse\if@twocolumn\@restonecoltrue\onecolumn + \else \newpage \fi \thispagestyle{empty}\c@page\z@} +\def\endtitlepage{\if@restonecol\twocolumn \else \newpage \fi} + +% standard values from article.cls +\arraycolsep 5pt +\arrayrulewidth .4pt +\doublerulesep 2pt + +\tabcolsep 6pt +\tabbingsep 0.5em + + +%% FOOTNOTES +% +%\skip\footins 10pt plus 4pt minus 2pt +% V1.6 respond to changes in font size +% space added above the footnotes (if present) +\skip\footins 0.9\baselineskip plus 0.4\baselineskip minus 0.2\baselineskip + +% V1.6, we need to make \footnotesep responsive to changes +% in \baselineskip or strange spacings will result when in +% draft mode. Here is a little LaTeX secret - \footnotesep +% determines the height of an invisible strut that is placed +% *above* the baseline of footnotes after the first. Since +% LaTeX considers the space for characters to be 0.7/baselineskip +% above the baseline and 0.3/baselineskip below it, we need to +% use 0.7/baselineskip as a \footnotesep to maintain equal spacing +% between all the lines of the footnotes. IEEE often uses a tad +% more, so use 0.8\baselineskip. This slightly larger value also helps +% the text to clear the footnote marks. Note that \thanks in IEEEtran +% uses its own value of \footnotesep which is set in \maketitle. +{\footnotesize +\global\footnotesep 0.8\baselineskip} + + +\skip\@mpfootins = \skip\footins +\fboxsep = 3pt +\fboxrule = .4pt +% V1.6 use 1em, then use LaTeX2e's \@makefnmark +% Note that IEEE normally *left* aligns the footnote marks, so we don't need +% box resizing tricks here. +\long\def\@makefntext#1{\parindent 1em\indent\hbox{\@makefnmark}#1}% V1.6 use 1em +% V1.7 compsoc does not use superscipts for footnote marks +\ifCLASSOPTIONcompsoc +\def\@IEEEcompsocmakefnmark{\hbox{\normalfont\@thefnmark.\ }} +\long\def\@makefntext#1{\parindent 1em\indent\hbox{\@IEEEcompsocmakefnmark}#1} +\fi + +% IEEE does not use footnote rules +\def\footnoterule{} + +% V1.7 for compsoc, IEEE uses a footnote rule only for \thanks. We devise a "one-shot" +% system to implement this. +\newif\if@IEEEenableoneshotfootnoterule +\@IEEEenableoneshotfootnoterulefalse +\ifCLASSOPTIONcompsoc +\def\footnoterule{\relax\if@IEEEenableoneshotfootnoterule +\kern-5pt +\hbox to \columnwidth{\hfill\vrule width 0.5\columnwidth height 0.4pt\hfill} +\kern4.6pt +\global\@IEEEenableoneshotfootnoterulefalse +\else +\relax +\fi} +\fi + +% V1.6 do not allow LaTeX to break a footnote across multiple pages +\interfootnotelinepenalty=10000 + +% V1.6 discourage breaks within equations +% Note that amsmath normally sets this to 10000, +% but LaTeX2e normally uses 100. +\interdisplaylinepenalty=2500 + +% default allows section depth up to /paragraph +\setcounter{secnumdepth}{4} + +% technotes do not allow /paragraph +\ifCLASSOPTIONtechnote + \setcounter{secnumdepth}{3} +\fi +% neither do compsoc conferences +\@IEEEcompsocconfonly{\setcounter{secnumdepth}{3}} + + +\newcounter{section} +\newcounter{subsection}[section] +\newcounter{subsubsection}[subsection] +\newcounter{paragraph}[subsubsection] + +% used only by IEEEtran's IEEEeqnarray as other packages may +% have their own, different, implementations +\newcounter{IEEEsubequation}[equation] + +% as shown when called by user from \ref, \label and in table of contents +\def\theequation{\arabic{equation}} % 1 +\def\theIEEEsubequation{\theequation\alph{IEEEsubequation}} % 1a (used only by IEEEtran's IEEEeqnarray) +\ifCLASSOPTIONcompsoc +% compsoc is all arabic +\def\thesection{\arabic{section}} +\def\thesubsection{\thesection.\arabic{subsection}} +\def\thesubsubsection{\thesubsection.\arabic{subsubsection}} +\def\theparagraph{\thesubsubsection.\arabic{paragraph}} +\else +\def\thesection{\Roman{section}} % I +% V1.7, \mbox prevents breaks around - +\def\thesubsection{\mbox{\thesection-\Alph{subsection}}} % I-A +% V1.7 use I-A1 format used by IEEE rather than I-A.1 +\def\thesubsubsection{\thesubsection\arabic{subsubsection}} % I-A1 +\def\theparagraph{\thesubsubsection\alph{paragraph}} % I-A1a +\fi + +% From Heiko Oberdiek. Because of the \mbox in \thesubsection, we need to +% tell hyperref to disable the \mbox command when making PDF bookmarks. +% This done already with hyperref.sty version 6.74o and later, but +% it will not hurt to do it here again for users of older versions. +\@ifundefined{pdfstringdefPreHook}{\let\pdfstringdefPreHook\@empty}{}% +\g@addto@macro\pdfstringdefPreHook{\let\mbox\relax} + + +% Main text forms (how shown in main text headings) +% V1.6, using \thesection in \thesectiondis allows changes +% in the former to automatically appear in the latter +\ifCLASSOPTIONcompsoc + \ifCLASSOPTIONconference% compsoc conference + \def\thesectiondis{\thesection.} + \def\thesubsectiondis{\thesectiondis\arabic{subsection}.} + \def\thesubsubsectiondis{\thesubsectiondis\arabic{subsubsection}.} + \def\theparagraphdis{\thesubsubsectiondis\arabic{paragraph}.} + \else% compsoc not conferencs + \def\thesectiondis{\thesection} + \def\thesubsectiondis{\thesectiondis.\arabic{subsection}} + \def\thesubsubsectiondis{\thesubsectiondis.\arabic{subsubsection}} + \def\theparagraphdis{\thesubsubsectiondis.\arabic{paragraph}} + \fi +\else% not compsoc + \def\thesectiondis{\thesection.} % I. + \def\thesubsectiondis{\Alph{subsection}.} % B. + \def\thesubsubsectiondis{\arabic{subsubsection})} % 3) + \def\theparagraphdis{\alph{paragraph})} % d) +\fi + +% just like LaTeX2e's \@eqnnum +\def\theequationdis{{\normalfont \normalcolor (\theequation)}}% (1) +% IEEEsubequation used only by IEEEtran's IEEEeqnarray +\def\theIEEEsubequationdis{{\normalfont \normalcolor (\theIEEEsubequation)}}% (1a) +% redirect LaTeX2e's equation number display and all that depend on +% it, through IEEEtran's \theequationdis +\def\@eqnnum{\theequationdis} + + + +% V1.7 provide string macros as article.cls does +\def\contentsname{Contents} +\def\listfigurename{List of Figures} +\def\listtablename{List of Tables} +\def\refname{References} +\def\indexname{Index} +\def\figurename{Fig.} +\def\tablename{TABLE} +\@IEEEcompsocconfonly{\def\figurename{Figure}\def\tablename{Table}} +\def\partname{Part} +\def\appendixname{Appendix} +\def\abstractname{Abstract} +% IEEE specific names +\def\IEEEkeywordsname{Index Terms} +\def\IEEEproofname{Proof} + + +% LIST OF FIGURES AND TABLES AND TABLE OF CONTENTS +% +\def\@pnumwidth{1.55em} +\def\@tocrmarg{2.55em} +\def\@dotsep{4.5} +\setcounter{tocdepth}{3} + +% adjusted some spacings here so that section numbers will not easily +% collide with the section titles. +% VIII; VIII-A; and VIII-A.1 are usually the worst offenders. +% MDS 1/2001 +\def\tableofcontents{\section*{\contentsname}\@starttoc{toc}} +\def\l@section#1#2{\addpenalty{\@secpenalty}\addvspace{1.0em plus 1pt}% + \@tempdima 2.75em \begingroup \parindent \z@ \rightskip \@pnumwidth% + \parfillskip-\@pnumwidth {\bfseries\leavevmode #1}\hfil\hbox to\@pnumwidth{\hss #2}\par% + \endgroup} +% argument format #1:level, #2:labelindent,#3:labelsep +\def\l@subsection{\@dottedtocline{2}{2.75em}{3.75em}} +\def\l@subsubsection{\@dottedtocline{3}{6.5em}{4.5em}} +% must provide \l@ defs for ALL sublevels EVEN if tocdepth +% is such as they will not appear in the table of contents +% these defs are how TOC knows what level these things are! +\def\l@paragraph{\@dottedtocline{4}{6.5em}{5.5em}} +\def\l@subparagraph{\@dottedtocline{5}{6.5em}{6.5em}} +\def\listoffigures{\section*{\listfigurename}\@starttoc{lof}} +\def\l@figure{\@dottedtocline{1}{0em}{2.75em}} +\def\listoftables{\section*{\listtablename}\@starttoc{lot}} +\let\l@table\l@figure + + +%% Definitions for floats +%% +%% Normal Floats +\floatsep 1\baselineskip plus 0.2\baselineskip minus 0.2\baselineskip +\textfloatsep 1.7\baselineskip plus 0.2\baselineskip minus 0.4\baselineskip +\@fptop 0pt plus 1fil +\@fpsep 0.75\baselineskip plus 2fil +\@fpbot 0pt plus 1fil +\def\topfraction{0.9} +\def\bottomfraction{0.4} +\def\floatpagefraction{0.8} +% V1.7, let top floats approach 90% of page +\def\textfraction{0.1} + +%% Double Column Floats +\dblfloatsep 1\baselineskip plus 0.2\baselineskip minus 0.2\baselineskip + +\dbltextfloatsep 1.7\baselineskip plus 0.2\baselineskip minus 0.4\baselineskip +% Note that it would be nice if the rubber here actually worked in LaTeX2e. +% There is a long standing limitation in LaTeX, first discovered (to the best +% of my knowledge) by Alan Jeffrey in 1992. LaTeX ignores the stretchable +% portion of \dbltextfloatsep, and as a result, double column figures can and +% do result in an non-integer number of lines in the main text columns with +% underfull vbox errors as a consequence. A post to comp.text.tex +% by Donald Arseneau confirms that this had not yet been fixed in 1998. +% IEEEtran V1.6 will fix this problem for you in the titles, but it doesn't +% protect you from other double floats. Happy vspace'ing. + +\@dblfptop 0pt plus 1fil +\@dblfpsep 0.75\baselineskip plus 2fil +\@dblfpbot 0pt plus 1fil +\def\dbltopfraction{0.8} +\def\dblfloatpagefraction{0.8} +\setcounter{dbltopnumber}{4} + +\intextsep 1\baselineskip plus 0.2\baselineskip minus 0.2\baselineskip +\setcounter{topnumber}{2} +\setcounter{bottomnumber}{2} +\setcounter{totalnumber}{4} + + + +% article class provides these, we should too. +\newlength\abovecaptionskip +\newlength\belowcaptionskip +% but only \abovecaptionskip is used above figure captions and *below* table +% captions +\setlength\abovecaptionskip{0.5\baselineskip} +\setlength\belowcaptionskip{0pt} +% V1.6 create hooks in case the caption spacing ever needs to be +% overridden by a user +\def\@IEEEfigurecaptionsepspace{\vskip\abovecaptionskip\relax}% +\def\@IEEEtablecaptionsepspace{\vskip\abovecaptionskip\relax}% + + +% 1.6b revise caption system so that \@makecaption uses two arguments +% as with LaTeX2e. Otherwise, there will be problems when using hyperref. +\def\@IEEEtablestring{table} + +\ifCLASSOPTIONcompsoc +% V1.7 compsoc \@makecaption +\ifCLASSOPTIONconference% compsoc conference +\long\def\@makecaption#1#2{% +% test if is a for a figure or table +\ifx\@captype\@IEEEtablestring% +% if a table, do table caption +\normalsize\begin{center}{\normalfont\sffamily\normalsize {#1.}~ #2}\end{center}% +\@IEEEtablecaptionsepspace +% if not a table, format it as a figure +\else +\@IEEEfigurecaptionsepspace +\setbox\@tempboxa\hbox{\normalfont\sffamily\normalsize {#1.}~ #2}% +\ifdim \wd\@tempboxa >\hsize% +% if caption is longer than a line, let it wrap around +\setbox\@tempboxa\hbox{\normalfont\sffamily\normalsize {#1.}~ }% +\parbox[t]{\hsize}{\normalfont\sffamily\normalsize \noindent\unhbox\@tempboxa#2}% +% if caption is shorter than a line, center +\else% +\hbox to\hsize{\normalfont\sffamily\normalsize\hfil\box\@tempboxa\hfil}% +\fi\fi} +\else% nonconference compsoc +\long\def\@makecaption#1#2{% +% test if is a for a figure or table +\ifx\@captype\@IEEEtablestring% +% if a table, do table caption +\normalsize\begin{center}{\normalfont\sffamily\normalsize #1}\\{\normalfont\sffamily\normalsize #2}\end{center}% +\@IEEEtablecaptionsepspace +% if not a table, format it as a figure +\else +\@IEEEfigurecaptionsepspace +\setbox\@tempboxa\hbox{\normalfont\sffamily\normalsize {#1.}~ #2}% +\ifdim \wd\@tempboxa >\hsize% +% if caption is longer than a line, let it wrap around +\setbox\@tempboxa\hbox{\normalfont\sffamily\normalsize {#1.}~ }% +\parbox[t]{\hsize}{\normalfont\sffamily\normalsize \noindent\unhbox\@tempboxa#2}% +% if caption is shorter than a line, left justify +\else% +\hbox to\hsize{\normalfont\sffamily\normalsize\box\@tempboxa\hfil}% +\fi\fi} +\fi + +\else% traditional noncompsoc \@makecaption +\long\def\@makecaption#1#2{% +% test if is a for a figure or table +\ifx\@captype\@IEEEtablestring% +% if a table, do table caption +\footnotesize\begin{center}{\normalfont\footnotesize #1}\\{\normalfont\footnotesize\scshape #2}\end{center}% +\@IEEEtablecaptionsepspace +% if not a table, format it as a figure +\else +\@IEEEfigurecaptionsepspace +% 3/2001 use footnotesize, not small; use two nonbreaking spaces, not one +\setbox\@tempboxa\hbox{\normalfont\footnotesize {#1.}~~ #2}% +\ifdim \wd\@tempboxa >\hsize% +% if caption is longer than a line, let it wrap around +\setbox\@tempboxa\hbox{\normalfont\footnotesize {#1.}~~ }% +\parbox[t]{\hsize}{\normalfont\footnotesize\noindent\unhbox\@tempboxa#2}% +% if caption is shorter than a line, center if conference, left justify otherwise +\else% +\ifCLASSOPTIONconference \hbox to\hsize{\normalfont\footnotesize\hfil\box\@tempboxa\hfil}% +\else \hbox to\hsize{\normalfont\footnotesize\box\@tempboxa\hfil}% +\fi\fi\fi} +\fi + + + +% V1.7 disable captions class option, do so in a way that retains operation of \label +% within \caption +\ifCLASSOPTIONcaptionsoff +\long\def\@makecaption#1#2{\vspace*{2em}\footnotesize\begin{center}{\footnotesize #1}\end{center}% +\let\@IEEEtemporiglabeldefsave\label +\let\@IEEEtemplabelargsave\relax +\def\label##1{\gdef\@IEEEtemplabelargsave{##1}}% +\setbox\@tempboxa\hbox{#2}% +\let\label\@IEEEtemporiglabeldefsave +\ifx\@IEEEtemplabelargsave\relax\else\label{\@IEEEtemplabelargsave}\fi} +\fi + + +% V1.7 define end environments with \def not \let so as to work OK with +% preview-latex +\newcounter{figure} +\def\thefigure{\@arabic\c@figure} +\def\fps@figure{tbp} +\def\ftype@figure{1} +\def\ext@figure{lof} +\def\fnum@figure{\figurename~\thefigure} +\def\figure{\@float{figure}} +\def\endfigure{\end@float} +\@namedef{figure*}{\@dblfloat{figure}} +\@namedef{endfigure*}{\end@dblfloat} +\newcounter{table} +\ifCLASSOPTIONcompsoc +\def\thetable{\arabic{table}} +\else +\def\thetable{\@Roman\c@table} +\fi +\def\fps@table{tbp} +\def\ftype@table{2} +\def\ext@table{lot} +\def\fnum@table{\tablename~\thetable} +% V1.6 IEEE uses 8pt text for tables +% to default to footnotesize, we hack into LaTeX2e's \@floatboxreset and pray +\def\table{\def\@floatboxreset{\reset@font\footnotesize\@setminipage}\@float{table}} +\def\endtable{\end@float} +% v1.6b double column tables need to default to footnotesize as well. +\@namedef{table*}{\def\@floatboxreset{\reset@font\footnotesize\@setminipage}\@dblfloat{table}} +\@namedef{endtable*}{\end@dblfloat} + + + + +%% +%% START OF IEEEeqnarry DEFINITIONS +%% +%% Inspired by the concepts, examples, and previous works of LaTeX +%% coders and developers such as Donald Arseneau, Fred Bartlett, +%% David Carlisle, Tony Liu, Frank Mittelbach, Piet van Oostrum, +%% Roland Winkler and Mark Wooding. +%% I don't make the claim that my work here is even near their calibre. ;) + + +% hook to allow easy changeover to IEEEtran.cls/tools.sty error reporting +\def\@IEEEclspkgerror{\ClassError{IEEEtran}} + +\newif\if@IEEEeqnarraystarform% flag to indicate if the environment was called as the star form +\@IEEEeqnarraystarformfalse + +\newif\if@advanceIEEEeqncolcnt% tracks if the environment should advance the col counter +% allows a way to make an \IEEEeqnarraybox that can be used within an \IEEEeqnarray +% used by IEEEeqnarraymulticol so that it can work properly in both +\@advanceIEEEeqncolcnttrue + +\newcount\@IEEEeqnnumcols % tracks how many IEEEeqnarray cols are defined +\newcount\@IEEEeqncolcnt % tracks how many IEEEeqnarray cols the user actually used + + +% The default math style used by the columns +\def\IEEEeqnarraymathstyle{\displaystyle} +% The default text style used by the columns +% default to using the current font +\def\IEEEeqnarraytextstyle{\relax} + +% like the iedlistdecl but for \IEEEeqnarray +\def\IEEEeqnarraydecl{\relax} +\def\IEEEeqnarrayboxdecl{\relax} + +% \yesnumber is the opposite of \nonumber +% a novel concept with the same def as the equationarray package +% However, we give IEEE versions too since some LaTeX packages such as +% the MDWtools mathenv.sty redefine \nonumber to something else. +\providecommand{\yesnumber}{\global\@eqnswtrue} +\def\IEEEyesnumber{\global\@eqnswtrue} +\def\IEEEnonumber{\global\@eqnswfalse} + + +\def\IEEEyessubnumber{\global\@IEEEissubequationtrue\global\@eqnswtrue% +\if@IEEEeqnarrayISinner% only do something inside an IEEEeqnarray +\if@IEEElastlinewassubequation\addtocounter{equation}{-1}\else\setcounter{IEEEsubequation}{1}\fi% +\def\@currentlabel{\p@IEEEsubequation\theIEEEsubequation}\fi} + +% flag to indicate that an equation is a sub equation +\newif\if@IEEEissubequation% +\@IEEEissubequationfalse + +% allows users to "push away" equations that get too close to the equation numbers +\def\IEEEeqnarraynumspace{\hphantom{\if@IEEEissubequation\theIEEEsubequationdis\else\theequationdis\fi}} + +% provides a way to span multiple columns within IEEEeqnarray environments +% will consider \if@advanceIEEEeqncolcnt before globally advancing the +% column counter - so as to work within \IEEEeqnarraybox +% usage: \IEEEeqnarraymulticol{number cols. to span}{col type}{cell text} +\long\def\IEEEeqnarraymulticol#1#2#3{\multispan{#1}% +% check if column is defined +\relax\expandafter\ifx\csname @IEEEeqnarraycolDEF#2\endcsname\@IEEEeqnarraycolisdefined% +\csname @IEEEeqnarraycolPRE#2\endcsname#3\relax\relax\relax\relax\relax% +\relax\relax\relax\relax\relax\csname @IEEEeqnarraycolPOST#2\endcsname% +\else% if not, error and use default type +\@IEEEclspkgerror{Invalid column type "#2" in \string\IEEEeqnarraymulticol.\MessageBreak +Using a default centering column instead}% +{You must define IEEEeqnarray column types before use.}% +\csname @IEEEeqnarraycolPRE@IEEEdefault\endcsname#3\relax\relax\relax\relax\relax% +\relax\relax\relax\relax\relax\csname @IEEEeqnarraycolPOST@IEEEdefault\endcsname% +\fi% +% advance column counter only if the IEEEeqnarray environment wants it +\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by #1\relax\fi} + +% like \omit, but maintains track of the column counter for \IEEEeqnarray +\def\IEEEeqnarrayomit{\omit\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by 1\relax\fi} + + +% provides a way to define a letter referenced column type +% usage: \IEEEeqnarraydefcol{col. type letter/name}{pre insertion text}{post insertion text} +\def\IEEEeqnarraydefcol#1#2#3{\expandafter\def\csname @IEEEeqnarraycolPRE#1\endcsname{#2}% +\expandafter\def\csname @IEEEeqnarraycolPOST#1\endcsname{#3}% +\expandafter\def\csname @IEEEeqnarraycolDEF#1\endcsname{1}} + + +% provides a way to define a numerically referenced inter-column glue types +% usage: \IEEEeqnarraydefcolsep{col. glue number}{glue definition} +\def\IEEEeqnarraydefcolsep#1#2{\expandafter\def\csname @IEEEeqnarraycolSEP\romannumeral #1\endcsname{#2}% +\expandafter\def\csname @IEEEeqnarraycolSEPDEF\romannumeral #1\endcsname{1}} + + +\def\@IEEEeqnarraycolisdefined{1}% just a macro for 1, used for checking undefined column types + + +% expands and appends the given argument to the \@IEEEtrantmptoksA token list +% used to build up the \halign preamble +\def\@IEEEappendtoksA#1{\edef\@@IEEEappendtoksA{\@IEEEtrantmptoksA={\the\@IEEEtrantmptoksA #1}}% +\@@IEEEappendtoksA} + +% also appends to \@IEEEtrantmptoksA, but does not expand the argument +% uses \toks8 as a scratchpad register +\def\@IEEEappendNOEXPANDtoksA#1{\toks8={#1}% +\edef\@@IEEEappendNOEXPANDtoksA{\@IEEEtrantmptoksA={\the\@IEEEtrantmptoksA\the\toks8}}% +\@@IEEEappendNOEXPANDtoksA} + +% define some common column types for the user +% math +\IEEEeqnarraydefcol{l}{$\IEEEeqnarraymathstyle}{$\hfil} +\IEEEeqnarraydefcol{c}{\hfil$\IEEEeqnarraymathstyle}{$\hfil} +\IEEEeqnarraydefcol{r}{\hfil$\IEEEeqnarraymathstyle}{$} +\IEEEeqnarraydefcol{L}{$\IEEEeqnarraymathstyle{}}{{}$\hfil} +\IEEEeqnarraydefcol{C}{\hfil$\IEEEeqnarraymathstyle{}}{{}$\hfil} +\IEEEeqnarraydefcol{R}{\hfil$\IEEEeqnarraymathstyle{}}{{}$} +% text +\IEEEeqnarraydefcol{s}{\IEEEeqnarraytextstyle}{\hfil} +\IEEEeqnarraydefcol{t}{\hfil\IEEEeqnarraytextstyle}{\hfil} +\IEEEeqnarraydefcol{u}{\hfil\IEEEeqnarraytextstyle}{} + +% vertical rules +\IEEEeqnarraydefcol{v}{}{\vrule width\arrayrulewidth} +\IEEEeqnarraydefcol{vv}{\vrule width\arrayrulewidth\hfil}{\hfil\vrule width\arrayrulewidth} +\IEEEeqnarraydefcol{V}{}{\vrule width\arrayrulewidth\hskip\doublerulesep\vrule width\arrayrulewidth} +\IEEEeqnarraydefcol{VV}{\vrule width\arrayrulewidth\hskip\doublerulesep\vrule width\arrayrulewidth\hfil}% +{\hfil\vrule width\arrayrulewidth\hskip\doublerulesep\vrule width\arrayrulewidth} + +% horizontal rules +\IEEEeqnarraydefcol{h}{}{\leaders\hrule height\arrayrulewidth\hfil} +\IEEEeqnarraydefcol{H}{}{\leaders\vbox{\hrule width\arrayrulewidth\vskip\doublerulesep\hrule width\arrayrulewidth}\hfil} + +% plain +\IEEEeqnarraydefcol{x}{}{} +\IEEEeqnarraydefcol{X}{$}{$} + +% the default column type to use in the event a column type is not defined +\IEEEeqnarraydefcol{@IEEEdefault}{\hfil$\IEEEeqnarraymathstyle}{$\hfil} + + +% a zero tabskip (used for "-" col types) +\def\@IEEEeqnarraycolSEPzero{0pt plus 0pt minus 0pt} +% a centering tabskip (used for "+" col types) +\def\@IEEEeqnarraycolSEPcenter{1000pt plus 0pt minus 1000pt} + +% top level default tabskip glues for the start, end, and inter-column +% may be reset within environments not always at the top level, e.g., \IEEEeqnarraybox +\edef\@IEEEeqnarraycolSEPdefaultstart{\@IEEEeqnarraycolSEPcenter}% default start glue +\edef\@IEEEeqnarraycolSEPdefaultend{\@IEEEeqnarraycolSEPcenter}% default end glue +\edef\@IEEEeqnarraycolSEPdefaultmid{\@IEEEeqnarraycolSEPzero}% default inter-column glue + + + +% creates a vertical rule that extends from the bottom to the top a a cell +% Provided in case other packages redefine \vline some other way. +% usage: \IEEEeqnarrayvrule[rule thickness] +% If no argument is provided, \arrayrulewidth will be used for the rule thickness. +\newcommand\IEEEeqnarrayvrule[1][\arrayrulewidth]{\vrule\@width#1\relax} + +% creates a blank separator row +% usage: \IEEEeqnarrayseprow[separation length][font size commands] +% default is \IEEEeqnarrayseprow[0.25\normalbaselineskip][\relax] +% blank arguments inherit the default values +% uses \skip5 as a scratch register - calls \@IEEEeqnarraystrutsize which uses more scratch registers +\def\IEEEeqnarrayseprow{\relax\@ifnextchar[{\@IEEEeqnarrayseprow}{\@IEEEeqnarrayseprow[0.25\normalbaselineskip]}} +\def\@IEEEeqnarrayseprow[#1]{\relax\@ifnextchar[{\@@IEEEeqnarrayseprow[#1]}{\@@IEEEeqnarrayseprow[#1][\relax]}} +\def\@@IEEEeqnarrayseprow[#1][#2]{\def\@IEEEeqnarrayseprowARGONE{#1}% +\ifx\@IEEEeqnarrayseprowARGONE\@empty% +% get the skip value, based on the font commands +% use skip5 because \IEEEeqnarraystrutsize uses \skip0, \skip2, \skip3 +% assign within a bogus box to confine the font changes +{\setbox0=\hbox{#2\relax\global\skip5=0.25\normalbaselineskip}}% +\else% +{\setbox0=\hbox{#2\relax\global\skip5=#1}}% +\fi% +\@IEEEeqnarrayhoptolastcolumn\IEEEeqnarraystrutsize{\skip5}{0pt}[\relax]\relax} + +% creates a blank separator row, but omits all the column templates +% usage: \IEEEeqnarrayseprowcut[separation length][font size commands] +% default is \IEEEeqnarrayseprowcut[0.25\normalbaselineskip][\relax] +% blank arguments inherit the default values +% uses \skip5 as a scratch register - calls \@IEEEeqnarraystrutsize which uses more scratch registers +\def\IEEEeqnarrayseprowcut{\multispan{\@IEEEeqnnumcols}\relax% span all the cols +% advance column counter only if the IEEEeqnarray environment wants it +\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by \@IEEEeqnnumcols\relax\fi% +\@ifnextchar[{\@IEEEeqnarrayseprowcut}{\@IEEEeqnarrayseprowcut[0.25\normalbaselineskip]}} +\def\@IEEEeqnarrayseprowcut[#1]{\relax\@ifnextchar[{\@@IEEEeqnarrayseprowcut[#1]}{\@@IEEEeqnarrayseprowcut[#1][\relax]}} +\def\@@IEEEeqnarrayseprowcut[#1][#2]{\def\@IEEEeqnarrayseprowARGONE{#1}% +\ifx\@IEEEeqnarrayseprowARGONE\@empty% +% get the skip value, based on the font commands +% use skip5 because \IEEEeqnarraystrutsize uses \skip0, \skip2, \skip3 +% assign within a bogus box to confine the font changes +{\setbox0=\hbox{#2\relax\global\skip5=0.25\normalbaselineskip}}% +\else% +{\setbox0=\hbox{#2\relax\global\skip5=#1}}% +\fi% +\IEEEeqnarraystrutsize{\skip5}{0pt}[\relax]\relax} + + + +% draws a single rule across all the columns optional +% argument determines the rule width, \arrayrulewidth is the default +% updates column counter as needed and turns off struts +% usage: \IEEEeqnarrayrulerow[rule line thickness] +\def\IEEEeqnarrayrulerow{\multispan{\@IEEEeqnnumcols}\relax% span all the cols +% advance column counter only if the IEEEeqnarray environment wants it +\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by \@IEEEeqnnumcols\relax\fi% +\@ifnextchar[{\@IEEEeqnarrayrulerow}{\@IEEEeqnarrayrulerow[\arrayrulewidth]}} +\def\@IEEEeqnarrayrulerow[#1]{\leaders\hrule height#1\hfil\relax% put in our rule +% turn off any struts +\IEEEeqnarraystrutsize{0pt}{0pt}[\relax]\relax} + + +% draws a double rule by using a single rule row, a separator row, and then +% another single rule row +% first optional argument determines the rule thicknesses, \arrayrulewidth is the default +% second optional argument determines the rule spacing, \doublerulesep is the default +% usage: \IEEEeqnarraydblrulerow[rule line thickness][rule spacing] +\def\IEEEeqnarraydblrulerow{\multispan{\@IEEEeqnnumcols}\relax% span all the cols +% advance column counter only if the IEEEeqnarray environment wants it +\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by \@IEEEeqnnumcols\relax\fi% +\@ifnextchar[{\@IEEEeqnarraydblrulerow}{\@IEEEeqnarraydblrulerow[\arrayrulewidth]}} +\def\@IEEEeqnarraydblrulerow[#1]{\relax\@ifnextchar[{\@@IEEEeqnarraydblrulerow[#1]}% +{\@@IEEEeqnarraydblrulerow[#1][\doublerulesep]}} +\def\@@IEEEeqnarraydblrulerow[#1][#2]{\def\@IEEEeqnarraydblrulerowARG{#1}% +% we allow the user to say \IEEEeqnarraydblrulerow[][] +\ifx\@IEEEeqnarraydblrulerowARG\@empty% +\@IEEEeqnarrayrulerow[\arrayrulewidth]% +\else% +\@IEEEeqnarrayrulerow[#1]\relax% +\fi% +\def\@IEEEeqnarraydblrulerowARG{#2}% +\ifx\@IEEEeqnarraydblrulerowARG\@empty% +\\\IEEEeqnarrayseprow[\doublerulesep][\relax]% +\else% +\\\IEEEeqnarrayseprow[#2][\relax]% +\fi% +\\\multispan{\@IEEEeqnnumcols}% +% advance column counter only if the IEEEeqnarray environment wants it +\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by \@IEEEeqnnumcols\relax\fi% +\def\@IEEEeqnarraydblrulerowARG{#1}% +\ifx\@IEEEeqnarraydblrulerowARG\@empty% +\@IEEEeqnarrayrulerow[\arrayrulewidth]% +\else% +\@IEEEeqnarrayrulerow[#1]% +\fi% +} + +% draws a double rule by using a single rule row, a separator (cutting) row, and then +% another single rule row +% first optional argument determines the rule thicknesses, \arrayrulewidth is the default +% second optional argument determines the rule spacing, \doublerulesep is the default +% usage: \IEEEeqnarraydblrulerow[rule line thickness][rule spacing] +\def\IEEEeqnarraydblrulerowcut{\multispan{\@IEEEeqnnumcols}\relax% span all the cols +% advance column counter only if the IEEEeqnarray environment wants it +\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by \@IEEEeqnnumcols\relax\fi% +\@ifnextchar[{\@IEEEeqnarraydblrulerowcut}{\@IEEEeqnarraydblrulerowcut[\arrayrulewidth]}} +\def\@IEEEeqnarraydblrulerowcut[#1]{\relax\@ifnextchar[{\@@IEEEeqnarraydblrulerowcut[#1]}% +{\@@IEEEeqnarraydblrulerowcut[#1][\doublerulesep]}} +\def\@@IEEEeqnarraydblrulerowcut[#1][#2]{\def\@IEEEeqnarraydblrulerowARG{#1}% +% we allow the user to say \IEEEeqnarraydblrulerow[][] +\ifx\@IEEEeqnarraydblrulerowARG\@empty% +\@IEEEeqnarrayrulerow[\arrayrulewidth]% +\else% +\@IEEEeqnarrayrulerow[#1]% +\fi% +\def\@IEEEeqnarraydblrulerowARG{#2}% +\ifx\@IEEEeqnarraydblrulerowARG\@empty% +\\\IEEEeqnarrayseprowcut[\doublerulesep][\relax]% +\else% +\\\IEEEeqnarrayseprowcut[#2][\relax]% +\fi% +\\\multispan{\@IEEEeqnnumcols}% +% advance column counter only if the IEEEeqnarray environment wants it +\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by \@IEEEeqnnumcols\relax\fi% +\def\@IEEEeqnarraydblrulerowARG{#1}% +\ifx\@IEEEeqnarraydblrulerowARG\@empty% +\@IEEEeqnarrayrulerow[\arrayrulewidth]% +\else% +\@IEEEeqnarrayrulerow[#1]% +\fi% +} + + + +% inserts a full row's worth of &'s +% relies on \@IEEEeqnnumcols to provide the correct number of columns +% uses \@IEEEtrantmptoksA, \count0 as scratch registers +\def\@IEEEeqnarrayhoptolastcolumn{\@IEEEtrantmptoksA={}\count0=1\relax% +\loop% add cols if the user did not use them all +\ifnum\count0<\@IEEEeqnnumcols\relax% +\@IEEEappendtoksA{&}% +\advance\count0 by 1\relax% update the col count +\repeat% +\the\@IEEEtrantmptoksA%execute the &'s +} + + + +\newif\if@IEEEeqnarrayISinner % flag to indicate if we are within the lines +\@IEEEeqnarrayISinnerfalse % of an IEEEeqnarray - after the IEEEeqnarraydecl + +\edef\@IEEEeqnarrayTHEstrutheight{0pt} % height and depth of IEEEeqnarray struts +\edef\@IEEEeqnarrayTHEstrutdepth{0pt} + +\edef\@IEEEeqnarrayTHEmasterstrutheight{0pt} % default height and depth of +\edef\@IEEEeqnarrayTHEmasterstrutdepth{0pt} % struts within an IEEEeqnarray + +\edef\@IEEEeqnarrayTHEmasterstrutHSAVE{0pt} % saved master strut height +\edef\@IEEEeqnarrayTHEmasterstrutDSAVE{0pt} % and depth + +\newif\if@IEEEeqnarrayusemasterstrut % flag to indicate that the master strut value +\@IEEEeqnarrayusemasterstruttrue % is to be used + + + +% saves the strut height and depth of the master strut +\def\@IEEEeqnarraymasterstrutsave{\relax% +\expandafter\skip0=\@IEEEeqnarrayTHEmasterstrutheight\relax% +\expandafter\skip2=\@IEEEeqnarrayTHEmasterstrutdepth\relax% +% remove stretchability +\dimen0\skip0\relax% +\dimen2\skip2\relax% +% save values +\edef\@IEEEeqnarrayTHEmasterstrutHSAVE{\the\dimen0}% +\edef\@IEEEeqnarrayTHEmasterstrutDSAVE{\the\dimen2}} + +% restores the strut height and depth of the master strut +\def\@IEEEeqnarraymasterstrutrestore{\relax% +\expandafter\skip0=\@IEEEeqnarrayTHEmasterstrutHSAVE\relax% +\expandafter\skip2=\@IEEEeqnarrayTHEmasterstrutDSAVE\relax% +% remove stretchability +\dimen0\skip0\relax% +\dimen2\skip2\relax% +% restore values +\edef\@IEEEeqnarrayTHEmasterstrutheight{\the\dimen0}% +\edef\@IEEEeqnarrayTHEmasterstrutdepth{\the\dimen2}} + + +% globally restores the strut height and depth to the +% master values and sets the master strut flag to true +\def\@IEEEeqnarraystrutreset{\relax% +\expandafter\skip0=\@IEEEeqnarrayTHEmasterstrutheight\relax% +\expandafter\skip2=\@IEEEeqnarrayTHEmasterstrutdepth\relax% +% remove stretchability +\dimen0\skip0\relax% +\dimen2\skip2\relax% +% restore values +\xdef\@IEEEeqnarrayTHEstrutheight{\the\dimen0}% +\xdef\@IEEEeqnarrayTHEstrutdepth{\the\dimen2}% +\global\@IEEEeqnarrayusemasterstruttrue} + + +% if the master strut is not to be used, make the current +% values of \@IEEEeqnarrayTHEstrutheight, \@IEEEeqnarrayTHEstrutdepth +% and the use master strut flag, global +% this allows user strut commands issued in the last column to be carried +% into the isolation/strut column +\def\@IEEEeqnarrayglobalizestrutstatus{\relax% +\if@IEEEeqnarrayusemasterstrut\else% +\xdef\@IEEEeqnarrayTHEstrutheight{\@IEEEeqnarrayTHEstrutheight}% +\xdef\@IEEEeqnarrayTHEstrutdepth{\@IEEEeqnarrayTHEstrutdepth}% +\global\@IEEEeqnarrayusemasterstrutfalse% +\fi} + + + +% usage: \IEEEeqnarraystrutsize{height}{depth}[font size commands] +% If called outside the lines of an IEEEeqnarray, sets the height +% and depth of both the master and local struts. If called inside +% an IEEEeqnarray line, sets the height and depth of the local strut +% only and sets the flag to indicate the use of the local strut +% values. If the height or depth is left blank, 0.7\normalbaselineskip +% and 0.3\normalbaselineskip will be used, respectively. +% The optional argument can be used to evaluate the lengths under +% a different font size and styles. If none is specified, the current +% font is used. +% uses scratch registers \skip0, \skip2, \skip3, \dimen0, \dimen2 +\def\IEEEeqnarraystrutsize#1#2{\relax\@ifnextchar[{\@IEEEeqnarraystrutsize{#1}{#2}}{\@IEEEeqnarraystrutsize{#1}{#2}[\relax]}} +\def\@IEEEeqnarraystrutsize#1#2[#3]{\def\@IEEEeqnarraystrutsizeARG{#1}% +\ifx\@IEEEeqnarraystrutsizeARG\@empty% +{\setbox0=\hbox{#3\relax\global\skip3=0.7\normalbaselineskip}}% +\skip0=\skip3\relax% +\else% arg one present +{\setbox0=\hbox{#3\relax\global\skip3=#1\relax}}% +\skip0=\skip3\relax% +\fi% if null arg +\def\@IEEEeqnarraystrutsizeARG{#2}% +\ifx\@IEEEeqnarraystrutsizeARG\@empty% +{\setbox0=\hbox{#3\relax\global\skip3=0.3\normalbaselineskip}}% +\skip2=\skip3\relax% +\else% arg two present +{\setbox0=\hbox{#3\relax\global\skip3=#2\relax}}% +\skip2=\skip3\relax% +\fi% if null arg +% remove stretchability, just to be safe +\dimen0\skip0\relax% +\dimen2\skip2\relax% +% dimen0 = height, dimen2 = depth +\if@IEEEeqnarrayISinner% inner does not touch master strut size +\edef\@IEEEeqnarrayTHEstrutheight{\the\dimen0}% +\edef\@IEEEeqnarrayTHEstrutdepth{\the\dimen2}% +\@IEEEeqnarrayusemasterstrutfalse% do not use master +\else% outer, have to set master strut too +\edef\@IEEEeqnarrayTHEmasterstrutheight{\the\dimen0}% +\edef\@IEEEeqnarrayTHEmasterstrutdepth{\the\dimen2}% +\edef\@IEEEeqnarrayTHEstrutheight{\the\dimen0}% +\edef\@IEEEeqnarrayTHEstrutdepth{\the\dimen2}% +\@IEEEeqnarrayusemasterstruttrue% use master strut +\fi} + + +% usage: \IEEEeqnarraystrutsizeadd{added height}{added depth}[font size commands] +% If called outside the lines of an IEEEeqnarray, adds the given height +% and depth to both the master and local struts. +% If called inside an IEEEeqnarray line, adds the given height and depth +% to the local strut only and sets the flag to indicate the use +% of the local strut values. +% In both cases, if a height or depth is left blank, 0pt is used instead. +% The optional argument can be used to evaluate the lengths under +% a different font size and styles. If none is specified, the current +% font is used. +% uses scratch registers \skip0, \skip2, \skip3, \dimen0, \dimen2 +\def\IEEEeqnarraystrutsizeadd#1#2{\relax\@ifnextchar[{\@IEEEeqnarraystrutsizeadd{#1}{#2}}{\@IEEEeqnarraystrutsizeadd{#1}{#2}[\relax]}} +\def\@IEEEeqnarraystrutsizeadd#1#2[#3]{\def\@IEEEeqnarraystrutsizearg{#1}% +\ifx\@IEEEeqnarraystrutsizearg\@empty% +\skip0=0pt\relax% +\else% arg one present +{\setbox0=\hbox{#3\relax\global\skip3=#1}}% +\skip0=\skip3\relax% +\fi% if null arg +\def\@IEEEeqnarraystrutsizearg{#2}% +\ifx\@IEEEeqnarraystrutsizearg\@empty% +\skip2=0pt\relax% +\else% arg two present +{\setbox0=\hbox{#3\relax\global\skip3=#2}}% +\skip2=\skip3\relax% +\fi% if null arg +% remove stretchability, just to be safe +\dimen0\skip0\relax% +\dimen2\skip2\relax% +% dimen0 = height, dimen2 = depth +\if@IEEEeqnarrayISinner% inner does not touch master strut size +% get local strut size +\expandafter\skip0=\@IEEEeqnarrayTHEstrutheight\relax% +\expandafter\skip2=\@IEEEeqnarrayTHEstrutdepth\relax% +% add it to the user supplied values +\advance\dimen0 by \skip0\relax% +\advance\dimen2 by \skip2\relax% +% update the local strut size +\edef\@IEEEeqnarrayTHEstrutheight{\the\dimen0}% +\edef\@IEEEeqnarrayTHEstrutdepth{\the\dimen2}% +\@IEEEeqnarrayusemasterstrutfalse% do not use master +\else% outer, have to set master strut too +% get master strut size +\expandafter\skip0=\@IEEEeqnarrayTHEmasterstrutheight\relax% +\expandafter\skip2=\@IEEEeqnarrayTHEmasterstrutdepth\relax% +% add it to the user supplied values +\advance\dimen0 by \skip0\relax% +\advance\dimen2 by \skip2\relax% +% update the local and master strut sizes +\edef\@IEEEeqnarrayTHEmasterstrutheight{\the\dimen0}% +\edef\@IEEEeqnarrayTHEmasterstrutdepth{\the\dimen2}% +\edef\@IEEEeqnarrayTHEstrutheight{\the\dimen0}% +\edef\@IEEEeqnarrayTHEstrutdepth{\the\dimen2}% +\@IEEEeqnarrayusemasterstruttrue% use master strut +\fi} + + +% allow user a way to see the struts +\newif\ifIEEEvisiblestruts +\IEEEvisiblestrutsfalse + +% inserts an invisible strut using the master or local strut values +% uses scratch registers \skip0, \skip2, \dimen0, \dimen2 +\def\@IEEEeqnarrayinsertstrut{\relax% +\if@IEEEeqnarrayusemasterstrut +% get master strut size +\expandafter\skip0=\@IEEEeqnarrayTHEmasterstrutheight\relax% +\expandafter\skip2=\@IEEEeqnarrayTHEmasterstrutdepth\relax% +\else% +% get local strut size +\expandafter\skip0=\@IEEEeqnarrayTHEstrutheight\relax% +\expandafter\skip2=\@IEEEeqnarrayTHEstrutdepth\relax% +\fi% +% remove stretchability, probably not needed +\dimen0\skip0\relax% +\dimen2\skip2\relax% +% dimen0 = height, dimen2 = depth +% allow user to see struts if desired +\ifIEEEvisiblestruts% +\vrule width0.2pt height\dimen0 depth\dimen2\relax% +\else% +\vrule width0pt height\dimen0 depth\dimen2\relax\fi} + + +% creates an invisible strut, useable even outside \IEEEeqnarray +% if \IEEEvisiblestrutstrue, the strut will be visible and 0.2pt wide. +% usage: \IEEEstrut[height][depth][font size commands] +% default is \IEEEstrut[0.7\normalbaselineskip][0.3\normalbaselineskip][\relax] +% blank arguments inherit the default values +% uses \dimen0, \dimen2, \skip0, \skip2 +\def\IEEEstrut{\relax\@ifnextchar[{\@IEEEstrut}{\@IEEEstrut[0.7\normalbaselineskip]}} +\def\@IEEEstrut[#1]{\relax\@ifnextchar[{\@@IEEEstrut[#1]}{\@@IEEEstrut[#1][0.3\normalbaselineskip]}} +\def\@@IEEEstrut[#1][#2]{\relax\@ifnextchar[{\@@@IEEEstrut[#1][#2]}{\@@@IEEEstrut[#1][#2][\relax]}} +\def\@@@IEEEstrut[#1][#2][#3]{\mbox{#3\relax% +\def\@IEEEstrutARG{#1}% +\ifx\@IEEEstrutARG\@empty% +\skip0=0.7\normalbaselineskip\relax% +\else% +\skip0=#1\relax% +\fi% +\def\@IEEEstrutARG{#2}% +\ifx\@IEEEstrutARG\@empty% +\skip2=0.3\normalbaselineskip\relax% +\else% +\skip2=#2\relax% +\fi% +% remove stretchability, probably not needed +\dimen0\skip0\relax% +\dimen2\skip2\relax% +\ifIEEEvisiblestruts% +\vrule width0.2pt height\dimen0 depth\dimen2\relax% +\else% +\vrule width0.0pt height\dimen0 depth\dimen2\relax\fi}} + + +% enables strut mode by setting a default strut size and then zeroing the +% \baselineskip, \lineskip, \lineskiplimit and \jot +\def\IEEEeqnarraystrutmode{\IEEEeqnarraystrutsize{0.7\normalbaselineskip}{0.3\normalbaselineskip}[\relax]% +\baselineskip=0pt\lineskip=0pt\lineskiplimit=0pt\jot=0pt} + + + +\def\IEEEeqnarray{\@IEEEeqnarraystarformfalse\@IEEEeqnarray} +\def\endIEEEeqnarray{\end@IEEEeqnarray} + +\@namedef{IEEEeqnarray*}{\@IEEEeqnarraystarformtrue\@IEEEeqnarray} +\@namedef{endIEEEeqnarray*}{\end@IEEEeqnarray} + + +% \IEEEeqnarray is an enhanced \eqnarray. +% The star form defaults to not putting equation numbers at the end of each row. +% usage: \IEEEeqnarray[decl]{cols} +\def\@IEEEeqnarray{\relax\@ifnextchar[{\@@IEEEeqnarray}{\@@IEEEeqnarray[\relax]}} +\def\@@IEEEeqnarray[#1]#2{% + % default to showing the equation number or not based on whether or not + % the star form was involked + \if@IEEEeqnarraystarform\global\@eqnswfalse + \else% not the star form + \global\@eqnswtrue + \fi% if star form + \@IEEEissubequationfalse% default to no subequations + \@IEEElastlinewassubequationfalse% assume last line is not a sub equation + \@IEEEeqnarrayISinnerfalse% not yet within the lines of the halign + \@IEEEeqnarraystrutsize{0pt}{0pt}[\relax]% turn off struts by default + \@IEEEeqnarrayusemasterstruttrue% use master strut till user asks otherwise + \IEEEvisiblestrutsfalse% diagnostic mode defaults to off + % no extra space unless the user specifically requests it + \lineskip=0pt\relax + \lineskiplimit=0pt\relax + \baselineskip=\normalbaselineskip\relax% + \jot=\IEEEnormaljot\relax% + \mathsurround\z@\relax% no extra spacing around math + \@advanceIEEEeqncolcnttrue% advance the col counter for each col the user uses, + % used in \IEEEeqnarraymulticol and in the preamble build + \stepcounter{equation}% advance equation counter before first line + \setcounter{IEEEsubequation}{0}% no subequation yet + \def\@currentlabel{\p@equation\theequation}% redefine the ref label + \IEEEeqnarraydecl\relax% allow a way for the user to make global overrides + #1\relax% allow user to override defaults + \let\\\@IEEEeqnarraycr% replace newline with one that can put in eqn. numbers + \global\@IEEEeqncolcnt\z@% col. count = 0 for first line + \@IEEEbuildpreamble #2\end\relax% build the preamble and put it into \@IEEEtrantmptoksA + % put in the column for the equation number + \ifnum\@IEEEeqnnumcols>0\relax\@IEEEappendtoksA{&}\fi% col separator for those after the first + \toks0={##}% + % advance the \@IEEEeqncolcnt for the isolation col, this helps with error checking + \@IEEEappendtoksA{\global\advance\@IEEEeqncolcnt by 1\relax}% + % add the isolation column + \@IEEEappendtoksA{\tabskip\z@skip\bgroup\the\toks0\egroup}% + % advance the \@IEEEeqncolcnt for the equation number col, this helps with error checking + \@IEEEappendtoksA{&\global\advance\@IEEEeqncolcnt by 1\relax}% + % add the equation number col to the preamble + \@IEEEappendtoksA{\tabskip\z@skip\hb@xt@\z@\bgroup\hss\the\toks0\egroup}% + % note \@IEEEeqnnumcols does not count the equation col or isolation col + % set the starting tabskip glue as determined by the preamble build + \tabskip=\@IEEEBPstartglue\relax + % begin the display alignment + \@IEEEeqnarrayISinnertrue% commands are now within the lines + $$\everycr{}\halign to\displaywidth\bgroup + % "exspand" the preamble + \span\the\@IEEEtrantmptoksA\cr} + +% enter isolation/strut column (or the next column if the user did not use +% every column), record the strut status, complete the columns, do the strut if needed, +% restore counters to correct values and exit +\def\end@IEEEeqnarray{\@IEEEeqnarrayglobalizestrutstatus&\@@IEEEeqnarraycr\egroup% +\if@IEEElastlinewassubequation\global\advance\c@IEEEsubequation\m@ne\fi% +\global\advance\c@equation\m@ne% +$$\@ignoretrue} + +% need a way to remember if last line is a subequation +\newif\if@IEEElastlinewassubequation% +\@IEEElastlinewassubequationfalse + +% IEEEeqnarray uses a modifed \\ instead of the plain \cr to +% end rows. This allows for things like \\*[vskip amount] +% This "cr" macros are modified versions those for LaTeX2e's eqnarray +% the {\ifnum0=`} braces must be kept away from the last column to avoid +% altering spacing of its math, so we use & to advance to the next column +% as there is an isolation/strut column after the user's columns +\def\@IEEEeqnarraycr{\@IEEEeqnarrayglobalizestrutstatus&% save strut status and advance to next column + {\ifnum0=`}\fi + \@ifstar{% + \global\@eqpen\@M\@IEEEeqnarrayYCR + }{% + \global\@eqpen\interdisplaylinepenalty \@IEEEeqnarrayYCR + }% +} + +\def\@IEEEeqnarrayYCR{\@testopt\@IEEEeqnarrayXCR\z@skip} + +\def\@IEEEeqnarrayXCR[#1]{% + \ifnum0=`{\fi}% + \@@IEEEeqnarraycr + \noalign{\penalty\@eqpen\vskip\jot\vskip #1\relax}}% + +\def\@@IEEEeqnarraycr{\@IEEEtrantmptoksA={}% clear token register + \advance\@IEEEeqncolcnt by -1\relax% adjust col count because of the isolation column + \ifnum\@IEEEeqncolcnt>\@IEEEeqnnumcols\relax + \@IEEEclspkgerror{Too many columns within the IEEEeqnarray\MessageBreak + environment}% + {Use fewer \string &'s or put more columns in the IEEEeqnarry column\MessageBreak + specifications.}\relax% + \else + \loop% add cols if the user did not use them all + \ifnum\@IEEEeqncolcnt<\@IEEEeqnnumcols\relax + \@IEEEappendtoksA{&}% + \advance\@IEEEeqncolcnt by 1\relax% update the col count + \repeat + % this number of &'s will take us the the isolation column + \fi + % execute the &'s + \the\@IEEEtrantmptoksA% + % handle the strut/isolation column + \@IEEEeqnarrayinsertstrut% do the strut if needed + \@IEEEeqnarraystrutreset% reset the strut system for next line or IEEEeqnarray + &% and enter the equation number column + % is this line needs an equation number, display it and advance the + % (sub)equation counters, record what type this line was + \if@eqnsw% + \if@IEEEissubequation\theIEEEsubequationdis\addtocounter{equation}{1}\stepcounter{IEEEsubequation}% + \global\@IEEElastlinewassubequationtrue% + \else% display a standard equation number, initialize the IEEEsubequation counter + \theequationdis\stepcounter{equation}\setcounter{IEEEsubequation}{0}% + \global\@IEEElastlinewassubequationfalse\fi% + \fi% + % reset the eqnsw flag to indicate default preference of the display of equation numbers + \if@IEEEeqnarraystarform\global\@eqnswfalse\else\global\@eqnswtrue\fi + \global\@IEEEissubequationfalse% reset the subequation flag + % reset the number of columns the user actually used + \global\@IEEEeqncolcnt\z@\relax + % the real end of the line + \cr} + + + + + +% \IEEEeqnarraybox is like \IEEEeqnarray except the box form puts everything +% inside a vtop, vbox, or vcenter box depending on the letter in the second +% optional argument (t,b,c). Vbox is the default. Unlike \IEEEeqnarray, +% equation numbers are not displayed and \IEEEeqnarraybox can be nested. +% \IEEEeqnarrayboxm is for math mode (like \array) and does not put the vbox +% within an hbox. +% \IEEEeqnarrayboxt is for text mode (like \tabular) and puts the vbox within +% a \hbox{$ $} construct. +% \IEEEeqnarraybox will auto detect whether to use \IEEEeqnarrayboxm or +% \IEEEeqnarrayboxt depending on the math mode. +% The third optional argument specifies the width this box is to be set to - +% natural width is the default. +% The * forms do not add \jot line spacing +% usage: \IEEEeqnarraybox[decl][pos][width]{cols} +\def\IEEEeqnarrayboxm{\@IEEEeqnarraystarformfalse\@IEEEeqnarrayboxHBOXSWfalse\@IEEEeqnarraybox} +\def\endIEEEeqnarrayboxm{\end@IEEEeqnarraybox} +\@namedef{IEEEeqnarrayboxm*}{\@IEEEeqnarraystarformtrue\@IEEEeqnarrayboxHBOXSWfalse\@IEEEeqnarraybox} +\@namedef{endIEEEeqnarrayboxm*}{\end@IEEEeqnarraybox} + +\def\IEEEeqnarrayboxt{\@IEEEeqnarraystarformfalse\@IEEEeqnarrayboxHBOXSWtrue\@IEEEeqnarraybox} +\def\endIEEEeqnarrayboxt{\end@IEEEeqnarraybox} +\@namedef{IEEEeqnarrayboxt*}{\@IEEEeqnarraystarformtrue\@IEEEeqnarrayboxHBOXSWtrue\@IEEEeqnarraybox} +\@namedef{endIEEEeqnarrayboxt*}{\end@IEEEeqnarraybox} + +\def\IEEEeqnarraybox{\@IEEEeqnarraystarformfalse\ifmmode\@IEEEeqnarrayboxHBOXSWfalse\else\@IEEEeqnarrayboxHBOXSWtrue\fi% +\@IEEEeqnarraybox} +\def\endIEEEeqnarraybox{\end@IEEEeqnarraybox} + +\@namedef{IEEEeqnarraybox*}{\@IEEEeqnarraystarformtrue\ifmmode\@IEEEeqnarrayboxHBOXSWfalse\else\@IEEEeqnarrayboxHBOXSWtrue\fi% +\@IEEEeqnarraybox} +\@namedef{endIEEEeqnarraybox*}{\end@IEEEeqnarraybox} + +% flag to indicate if the \IEEEeqnarraybox needs to put things into an hbox{$ $} +% for \vcenter in non-math mode +\newif\if@IEEEeqnarrayboxHBOXSW% +\@IEEEeqnarrayboxHBOXSWfalse + +\def\@IEEEeqnarraybox{\relax\@ifnextchar[{\@@IEEEeqnarraybox}{\@@IEEEeqnarraybox[\relax]}} +\def\@@IEEEeqnarraybox[#1]{\relax\@ifnextchar[{\@@@IEEEeqnarraybox[#1]}{\@@@IEEEeqnarraybox[#1][b]}} +\def\@@@IEEEeqnarraybox[#1][#2]{\relax\@ifnextchar[{\@@@@IEEEeqnarraybox[#1][#2]}{\@@@@IEEEeqnarraybox[#1][#2][\relax]}} + +% #1 = decl; #2 = t,b,c; #3 = width, #4 = col specs +\def\@@@@IEEEeqnarraybox[#1][#2][#3]#4{\@IEEEeqnarrayISinnerfalse % not yet within the lines of the halign + \@IEEEeqnarraymasterstrutsave% save current master strut values + \@IEEEeqnarraystrutsize{0pt}{0pt}[\relax]% turn off struts by default + \@IEEEeqnarrayusemasterstruttrue% use master strut till user asks otherwise + \IEEEvisiblestrutsfalse% diagnostic mode defaults to off + % no extra space unless the user specifically requests it + \lineskip=0pt\relax% + \lineskiplimit=0pt\relax% + \baselineskip=\normalbaselineskip\relax% + \jot=\IEEEnormaljot\relax% + \mathsurround\z@\relax% no extra spacing around math + % the default end glues are zero for an \IEEEeqnarraybox + \edef\@IEEEeqnarraycolSEPdefaultstart{\@IEEEeqnarraycolSEPzero}% default start glue + \edef\@IEEEeqnarraycolSEPdefaultend{\@IEEEeqnarraycolSEPzero}% default end glue + \edef\@IEEEeqnarraycolSEPdefaultmid{\@IEEEeqnarraycolSEPzero}% default inter-column glue + \@advanceIEEEeqncolcntfalse% do not advance the col counter for each col the user uses, + % used in \IEEEeqnarraymulticol and in the preamble build + \IEEEeqnarrayboxdecl\relax% allow a way for the user to make global overrides + #1\relax% allow user to override defaults + \let\\\@IEEEeqnarrayboxcr% replace newline with one that allows optional spacing + \@IEEEbuildpreamble #4\end\relax% build the preamble and put it into \@IEEEtrantmptoksA + % add an isolation column to the preamble to stop \\'s {} from getting into the last col + \ifnum\@IEEEeqnnumcols>0\relax\@IEEEappendtoksA{&}\fi% col separator for those after the first + \toks0={##}% + % add the isolation column to the preamble + \@IEEEappendtoksA{\tabskip\z@skip\bgroup\the\toks0\egroup}% + % set the starting tabskip glue as determined by the preamble build + \tabskip=\@IEEEBPstartglue\relax + % begin the alignment + \everycr{}% + % use only the very first token to determine the positioning + % this stops some problems when the user uses more than one letter, + % but is probably not worth the effort + % \noindent is used as a delimiter + \def\@IEEEgrabfirstoken##1##2\noindent{\let\@IEEEgrabbedfirstoken=##1}% + \@IEEEgrabfirstoken#2\relax\relax\noindent + % \@IEEEgrabbedfirstoken has the first token, the rest are discarded + % if we need to put things into and hbox and go into math mode, do so now + \if@IEEEeqnarrayboxHBOXSW \leavevmode \hbox \bgroup $\fi% + % use the appropriate vbox type + \if\@IEEEgrabbedfirstoken t\relax\vtop\else\if\@IEEEgrabbedfirstoken c\relax% + \vcenter\else\vbox\fi\fi\bgroup% + \@IEEEeqnarrayISinnertrue% commands are now within the lines + \ifx#3\relax\halign\else\halign to #3\relax\fi% + \bgroup + % "exspand" the preamble + \span\the\@IEEEtrantmptoksA\cr} + +% carry strut status and enter the isolation/strut column, +% exit from math mode if needed, and exit +\def\end@IEEEeqnarraybox{\@IEEEeqnarrayglobalizestrutstatus% carry strut status +&% enter isolation/strut column +\@IEEEeqnarrayinsertstrut% do strut if needed +\@IEEEeqnarraymasterstrutrestore% restore the previous master strut values +% reset the strut system for next IEEEeqnarray +% (sets local strut values back to previous master strut values) +\@IEEEeqnarraystrutreset% +% ensure last line, exit from halign, close vbox +\crcr\egroup\egroup% +% exit from math mode and close hbox if needed +\if@IEEEeqnarrayboxHBOXSW $\egroup\fi} + + + +% IEEEeqnarraybox uses a modifed \\ instead of the plain \cr to +% end rows. This allows for things like \\[vskip amount] +% This "cr" macros are modified versions those for LaTeX2e's eqnarray +% For IEEEeqnarraybox, \\* is the same as \\ +% the {\ifnum0=`} braces must be kept away from the last column to avoid +% altering spacing of its math, so we use & to advance to the isolation/strut column +% carry strut status into isolation/strut column +\def\@IEEEeqnarrayboxcr{\@IEEEeqnarrayglobalizestrutstatus% carry strut status +&% enter isolation/strut column +\@IEEEeqnarrayinsertstrut% do strut if needed +% reset the strut system for next line or IEEEeqnarray +\@IEEEeqnarraystrutreset% +{\ifnum0=`}\fi% +\@ifstar{\@IEEEeqnarrayboxYCR}{\@IEEEeqnarrayboxYCR}} + +% test and setup the optional argument to \\[] +\def\@IEEEeqnarrayboxYCR{\@testopt\@IEEEeqnarrayboxXCR\z@skip} + +% IEEEeqnarraybox does not automatically increase line spacing by \jot +\def\@IEEEeqnarrayboxXCR[#1]{\ifnum0=`{\fi}% +\cr\noalign{\if@IEEEeqnarraystarform\else\vskip\jot\fi\vskip#1\relax}} + + + +% starts the halign preamble build +\def\@IEEEbuildpreamble{\@IEEEtrantmptoksA={}% clear token register +\let\@IEEEBPcurtype=u%current column type is not yet known +\let\@IEEEBPprevtype=s%the previous column type was the start +\let\@IEEEBPnexttype=u%next column type is not yet known +% ensure these are valid +\def\@IEEEBPcurglue={0pt plus 0pt minus 0pt}% +\def\@IEEEBPcurcolname{@IEEEdefault}% name of current column definition +% currently acquired numerically referenced glue +% use a name that is easier to remember +\let\@IEEEBPcurnum=\@IEEEtrantmpcountA% +\@IEEEBPcurnum=0% +% tracks number of columns in the preamble +\@IEEEeqnnumcols=0% +% record the default end glues +\edef\@IEEEBPstartglue{\@IEEEeqnarraycolSEPdefaultstart}% +\edef\@IEEEBPendglue{\@IEEEeqnarraycolSEPdefaultend}% +% now parse the user's column specifications +\@@IEEEbuildpreamble} + + +% parses and builds the halign preamble +\def\@@IEEEbuildpreamble#1#2{\let\@@nextIEEEbuildpreamble=\@@IEEEbuildpreamble% +% use only the very first token to check the end +% \noindent is used as a delimiter as \end can be present here +\def\@IEEEgrabfirstoken##1##2\noindent{\let\@IEEEgrabbedfirstoken=##1}% +\@IEEEgrabfirstoken#1\relax\relax\noindent +\ifx\@IEEEgrabbedfirstoken\end\let\@@nextIEEEbuildpreamble=\@@IEEEfinishpreamble\else% +% identify current and next token type +\@IEEEgetcoltype{#1}{\@IEEEBPcurtype}{1}% current, error on invalid +\@IEEEgetcoltype{#2}{\@IEEEBPnexttype}{0}% next, no error on invalid next +% if curtype is a glue, get the glue def +\if\@IEEEBPcurtype g\@IEEEgetcurglue{#1}{\@IEEEBPcurglue}\fi% +% if curtype is a column, get the column def and set the current column name +\if\@IEEEBPcurtype c\@IEEEgetcurcol{#1}\fi% +% if curtype is a numeral, acquire the user defined glue +\if\@IEEEBPcurtype n\@IEEEprocessNcol{#1}\fi% +% process the acquired glue +\if\@IEEEBPcurtype g\@IEEEprocessGcol\fi% +% process the acquired col +\if\@IEEEBPcurtype c\@IEEEprocessCcol\fi% +% ready prevtype for next col spec. +\let\@IEEEBPprevtype=\@IEEEBPcurtype% +% be sure and put back the future token(s) as a group +\fi\@@nextIEEEbuildpreamble{#2}} + + +% executed just after preamble build is completed +% warn about zero cols, and if prevtype type = u, put in end tabskip glue +\def\@@IEEEfinishpreamble#1{\ifnum\@IEEEeqnnumcols<1\relax +\@IEEEclspkgerror{No column specifiers declared for IEEEeqnarray}% +{At least one column type must be declared for each IEEEeqnarray.}% +\fi%num cols less than 1 +%if last type undefined, set default end tabskip glue +\if\@IEEEBPprevtype u\@IEEEappendtoksA{\tabskip=\@IEEEBPendglue}\fi} + + +% Identify and return the column specifier's type code +\def\@IEEEgetcoltype#1#2#3{% +% use only the very first token to determine the type +% \noindent is used as a delimiter as \end can be present here +\def\@IEEEgrabfirstoken##1##2\noindent{\let\@IEEEgrabbedfirstoken=##1}% +\@IEEEgrabfirstoken#1\relax\relax\noindent +% \@IEEEgrabfirstoken has the first token, the rest are discarded +% n = number +% g = glue (any other char in catagory 12) +% c = letter +% e = \end +% u = undefined +% third argument: 0 = no error message, 1 = error on invalid char +\let#2=u\relax% assume invalid until know otherwise +\ifx\@IEEEgrabbedfirstoken\end\let#2=e\else +\ifcat\@IEEEgrabbedfirstoken\relax\else% screen out control sequences +\if0\@IEEEgrabbedfirstoken\let#2=n\else +\if1\@IEEEgrabbedfirstoken\let#2=n\else +\if2\@IEEEgrabbedfirstoken\let#2=n\else +\if3\@IEEEgrabbedfirstoken\let#2=n\else +\if4\@IEEEgrabbedfirstoken\let#2=n\else +\if5\@IEEEgrabbedfirstoken\let#2=n\else +\if6\@IEEEgrabbedfirstoken\let#2=n\else +\if7\@IEEEgrabbedfirstoken\let#2=n\else +\if8\@IEEEgrabbedfirstoken\let#2=n\else +\if9\@IEEEgrabbedfirstoken\let#2=n\else +\ifcat,\@IEEEgrabbedfirstoken\let#2=g\relax +\else\ifcat a\@IEEEgrabbedfirstoken\let#2=c\relax\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi +\if#2u\relax +\if0\noexpand#3\relax\else\@IEEEclspkgerror{Invalid character in column specifications}% +{Only letters, numerals and certain other symbols are allowed \MessageBreak +as IEEEeqnarray column specifiers.}\fi\fi} + + +% identify the current letter referenced column +% if invalid, use a default column +\def\@IEEEgetcurcol#1{\expandafter\ifx\csname @IEEEeqnarraycolDEF#1\endcsname\@IEEEeqnarraycolisdefined% +\def\@IEEEBPcurcolname{#1}\else% invalid column name +\@IEEEclspkgerror{Invalid column type "#1" in column specifications.\MessageBreak +Using a default centering column instead}% +{You must define IEEEeqnarray column types before use.}% +\def\@IEEEBPcurcolname{@IEEEdefault}\fi} + + +% identify and return the predefined (punctuation) glue value +\def\@IEEEgetcurglue#1#2{% +% ! = \! (neg small) -0.16667em (-3/18 em) +% , = \, (small) 0.16667em ( 3/18 em) +% : = \: (med) 0.22222em ( 4/18 em) +% ; = \; (large) 0.27778em ( 5/18 em) +% ' = \quad 1em +% " = \qquad 2em +% . = 0.5\arraycolsep +% / = \arraycolsep +% ? = 2\arraycolsep +% * = 1fil +% + = \@IEEEeqnarraycolSEPcenter +% - = \@IEEEeqnarraycolSEPzero +% Note that all em values are referenced to the math font (textfont2) fontdimen6 +% value for 1em. +% +% use only the very first token to determine the type +% this prevents errant tokens from getting in the main text +% \noindent is used as a delimiter here +\def\@IEEEgrabfirstoken##1##2\noindent{\let\@IEEEgrabbedfirstoken=##1}% +\@IEEEgrabfirstoken#1\relax\relax\noindent +% get the math font 1em value +% LaTeX2e's NFSS2 does not preload the fonts, but \IEEEeqnarray needs +% to gain access to the math (\textfont2) font's spacing parameters. +% So we create a bogus box here that uses the math font to ensure +% that \textfont2 is loaded and ready. If this is not done, +% the \textfont2 stuff here may not work. +% Thanks to Bernd Raichle for his 1997 post on this topic. +{\setbox0=\hbox{$\displaystyle\relax$}}% +% fontdimen6 has the width of 1em (a quad). +\@IEEEtrantmpdimenA=\fontdimen6\textfont2\relax% +% identify the glue value based on the first token +% we discard anything after the first +\if!\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=-0.16667\@IEEEtrantmpdimenA\edef#2{\the\@IEEEtrantmpdimenA}\else +\if,\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=0.16667\@IEEEtrantmpdimenA\edef#2{\the\@IEEEtrantmpdimenA}\else +\if:\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=0.22222\@IEEEtrantmpdimenA\edef#2{\the\@IEEEtrantmpdimenA}\else +\if;\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=0.27778\@IEEEtrantmpdimenA\edef#2{\the\@IEEEtrantmpdimenA}\else +\if'\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=1\@IEEEtrantmpdimenA\edef#2{\the\@IEEEtrantmpdimenA}\else +\if"\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=2\@IEEEtrantmpdimenA\edef#2{\the\@IEEEtrantmpdimenA}\else +\if.\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=0.5\arraycolsep\edef#2{\the\@IEEEtrantmpdimenA}\else +\if/\@IEEEgrabbedfirstoken\edef#2{\the\arraycolsep}\else +\if?\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=2\arraycolsep\edef#2{\the\@IEEEtrantmpdimenA}\else +\if *\@IEEEgrabbedfirstoken\edef#2{0pt plus 1fil minus 0pt}\else +\if+\@IEEEgrabbedfirstoken\edef#2{\@IEEEeqnarraycolSEPcenter}\else +\if-\@IEEEgrabbedfirstoken\edef#2{\@IEEEeqnarraycolSEPzero}\else +\edef#2{\@IEEEeqnarraycolSEPzero}% +\@IEEEclspkgerror{Invalid predefined inter-column glue type "#1" in\MessageBreak +column specifications. Using a default value of\MessageBreak +0pt instead}% +{Only !,:;'"./?*+ and - are valid predefined glue types in the\MessageBreak +IEEEeqnarray column specifications.}\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} + + + +% process a numerical digit from the column specification +% and look up the corresponding user defined glue value +% can transform current type from n to g or a as the user defined glue is acquired +\def\@IEEEprocessNcol#1{\if\@IEEEBPprevtype g% +\@IEEEclspkgerror{Back-to-back inter-column glue specifiers in column\MessageBreak +specifications. Ignoring consecutive glue specifiers\MessageBreak +after the first}% +{You cannot have two or more glue types next to each other\MessageBreak +in the IEEEeqnarray column specifications.}% +\let\@IEEEBPcurtype=a% abort this glue, future digits will be discarded +\@IEEEBPcurnum=0\relax% +\else% if we previously aborted a glue +\if\@IEEEBPprevtype a\@IEEEBPcurnum=0\let\@IEEEBPcurtype=a%maintain digit abortion +\else%acquire this number +% save the previous type before the numerical digits started +\if\@IEEEBPprevtype n\else\let\@IEEEBPprevsavedtype=\@IEEEBPprevtype\fi% +\multiply\@IEEEBPcurnum by 10\relax% +\advance\@IEEEBPcurnum by #1\relax% add in number, \relax is needed to stop TeX's number scan +\if\@IEEEBPnexttype n\else%close acquisition +\expandafter\ifx\csname @IEEEeqnarraycolSEPDEF\expandafter\romannumeral\number\@IEEEBPcurnum\endcsname\@IEEEeqnarraycolisdefined% +\edef\@IEEEBPcurglue{\csname @IEEEeqnarraycolSEP\expandafter\romannumeral\number\@IEEEBPcurnum\endcsname}% +\else%user glue not defined +\@IEEEclspkgerror{Invalid user defined inter-column glue type "\number\@IEEEBPcurnum" in\MessageBreak +column specifications. Using a default value of\MessageBreak +0pt instead}% +{You must define all IEEEeqnarray numerical inter-column glue types via\MessageBreak +\string\IEEEeqnarraydefcolsep \space before they are used in column specifications.}% +\edef\@IEEEBPcurglue{\@IEEEeqnarraycolSEPzero}% +\fi% glue defined or not +\let\@IEEEBPcurtype=g% change the type to reflect the acquired glue +\let\@IEEEBPprevtype=\@IEEEBPprevsavedtype% restore the prev type before this number glue +\@IEEEBPcurnum=0\relax%ready for next acquisition +\fi%close acquisition, get glue +\fi%discard or acquire number +\fi%prevtype glue or not +} + + +% process an acquired glue +% add any acquired column/glue pair to the preamble +\def\@IEEEprocessGcol{\if\@IEEEBPprevtype a\let\@IEEEBPcurtype=a%maintain previous glue abortions +\else +% if this is the start glue, save it, but do nothing else +% as this is not used in the preamble, but before +\if\@IEEEBPprevtype s\edef\@IEEEBPstartglue{\@IEEEBPcurglue}% +\else%not the start glue +\if\@IEEEBPprevtype g%ignore if back to back glues +\@IEEEclspkgerror{Back-to-back inter-column glue specifiers in column\MessageBreak +specifications. Ignoring consecutive glue specifiers\MessageBreak +after the first}% +{You cannot have two or more glue types next to each other\MessageBreak +in the IEEEeqnarray column specifications.}% +\let\@IEEEBPcurtype=a% abort this glue +\else% not a back to back glue +\if\@IEEEBPprevtype c\relax% if the previoustype was a col, add column/glue pair to preamble +\ifnum\@IEEEeqnnumcols>0\relax\@IEEEappendtoksA{&}\fi +\toks0={##}% +% make preamble advance col counter if this environment needs this +\if@advanceIEEEeqncolcnt\@IEEEappendtoksA{\global\advance\@IEEEeqncolcnt by 1\relax}\fi +% insert the column defintion into the preamble, being careful not to expand +% the column definition +\@IEEEappendtoksA{\tabskip=\@IEEEBPcurglue}% +\@IEEEappendNOEXPANDtoksA{\begingroup\csname @IEEEeqnarraycolPRE}% +\@IEEEappendtoksA{\@IEEEBPcurcolname}% +\@IEEEappendNOEXPANDtoksA{\endcsname}% +\@IEEEappendtoksA{\the\toks0}% +\@IEEEappendNOEXPANDtoksA{\relax\relax\relax\relax\relax% +\relax\relax\relax\relax\relax\csname @IEEEeqnarraycolPOST}% +\@IEEEappendtoksA{\@IEEEBPcurcolname}% +\@IEEEappendNOEXPANDtoksA{\endcsname\relax\relax\relax\relax\relax% +\relax\relax\relax\relax\relax\endgroup}% +\advance\@IEEEeqnnumcols by 1\relax%one more column in the preamble +\else% error: non-start glue with no pending column +\@IEEEclspkgerror{Inter-column glue specifier without a prior column\MessageBreak +type in the column specifications. Ignoring this glue\MessageBreak +specifier}% +{Except for the first and last positions, glue can be placed only\MessageBreak +between column types.}% +\let\@IEEEBPcurtype=a% abort this glue +\fi% previous was a column +\fi% back-to-back glues +\fi% is start column glue +\fi% prev type not a +} + + +% process an acquired letter referenced column and, if necessary, add it to the preamble +\def\@IEEEprocessCcol{\if\@IEEEBPnexttype g\else +\if\@IEEEBPnexttype n\else +% we have a column followed by something other than a glue (or numeral glue) +% so we must add this column to the preamble now +\ifnum\@IEEEeqnnumcols>0\relax\@IEEEappendtoksA{&}\fi%col separator for those after the first +\if\@IEEEBPnexttype e\@IEEEappendtoksA{\tabskip=\@IEEEBPendglue\relax}\else%put in end glue +\@IEEEappendtoksA{\tabskip=\@IEEEeqnarraycolSEPdefaultmid\relax}\fi% or default mid glue +\toks0={##}% +% make preamble advance col counter if this environment needs this +\if@advanceIEEEeqncolcnt\@IEEEappendtoksA{\global\advance\@IEEEeqncolcnt by 1\relax}\fi +% insert the column definition into the preamble, being careful not to expand +% the column definition +\@IEEEappendNOEXPANDtoksA{\begingroup\csname @IEEEeqnarraycolPRE}% +\@IEEEappendtoksA{\@IEEEBPcurcolname}% +\@IEEEappendNOEXPANDtoksA{\endcsname}% +\@IEEEappendtoksA{\the\toks0}% +\@IEEEappendNOEXPANDtoksA{\relax\relax\relax\relax\relax% +\relax\relax\relax\relax\relax\csname @IEEEeqnarraycolPOST}% +\@IEEEappendtoksA{\@IEEEBPcurcolname}% +\@IEEEappendNOEXPANDtoksA{\endcsname\relax\relax\relax\relax\relax% +\relax\relax\relax\relax\relax\endgroup}% +\advance\@IEEEeqnnumcols by 1\relax%one more column in the preamble +\fi%next type not numeral +\fi%next type not glue +} + + +%% +%% END OF IEEEeqnarry DEFINITIONS +%% + + + + +% set up the running headings, this complex because of all the different +% modes IEEEtran supports +\if@twoside + \ifCLASSOPTIONtechnote + \def\ps@headings{% + \def\@oddhead{\hbox{}\scriptsize\leftmark \hfil \thepage} + \def\@evenhead{\scriptsize\thepage \hfil \leftmark\hbox{}} + \ifCLASSOPTIONdraftcls + \ifCLASSOPTIONdraftclsnofoot + \def\@oddfoot{}\def\@evenfoot{}% + \else + \def\@oddfoot{\scriptsize\@date\hfil DRAFT} + \def\@evenfoot{\scriptsize DRAFT\hfil\@date} + \fi + \else + \def\@oddfoot{}\def\@evenfoot{} + \fi} + \else % not a technote + \def\ps@headings{% + \ifCLASSOPTIONconference + \def\@oddhead{} + \def\@evenhead{} + \else + \def\@oddhead{\hbox{}\scriptsize\rightmark \hfil \thepage} + \def\@evenhead{\scriptsize\thepage \hfil \leftmark\hbox{}} + \fi + \ifCLASSOPTIONdraftcls + \def\@oddhead{\hbox{}\scriptsize\rightmark \hfil \thepage} + \def\@evenhead{\scriptsize\thepage \hfil \leftmark\hbox{}} + \ifCLASSOPTIONdraftclsnofoot + \def\@oddfoot{}\def\@evenfoot{}% + \else + \def\@oddfoot{\scriptsize\@date\hfil DRAFT} + \def\@evenfoot{\scriptsize DRAFT\hfil\@date} + \fi + \else + \def\@oddfoot{}\def\@evenfoot{}% + \fi} + \fi +\else % single side +\def\ps@headings{% + \ifCLASSOPTIONconference + \def\@oddhead{} + \def\@evenhead{} + \else + \def\@oddhead{\hbox{}\scriptsize\leftmark \hfil \thepage} + \def\@evenhead{} + \fi + \ifCLASSOPTIONdraftcls + \def\@oddhead{\hbox{}\scriptsize\leftmark \hfil \thepage} + \def\@evenhead{} + \ifCLASSOPTIONdraftclsnofoot + \def\@oddfoot{} + \else + \def\@oddfoot{\scriptsize \@date \hfil DRAFT} + \fi + \else + \def\@oddfoot{} + \fi + \def\@evenfoot{}} +\fi + + +% title page style +\def\ps@IEEEtitlepagestyle{\def\@oddfoot{}\def\@evenfoot{}% +\ifCLASSOPTIONconference + \def\@oddhead{}% + \def\@evenhead{}% +\else + \def\@oddhead{\hbox{}\scriptsize\leftmark \hfil \thepage}% + \def\@evenhead{\scriptsize\thepage \hfil \leftmark\hbox{}}% +\fi +\ifCLASSOPTIONdraftcls + \def\@oddhead{\hbox{}\scriptsize\leftmark \hfil \thepage}% + \def\@evenhead{\scriptsize\thepage \hfil \leftmark\hbox{}}% + \ifCLASSOPTIONdraftclsnofoot\else + \def\@oddfoot{\scriptsize \@date\hfil DRAFT}% + \def\@evenfoot{\scriptsize DRAFT\hfil \@date}% + \fi +\else + % all non-draft mode footers + \if@IEEEusingpubid + % for title pages that are using a pubid + % do not repeat pubid if using peer review option + \ifCLASSOPTIONpeerreview + \else + \footskip 0pt% + \ifCLASSOPTIONcompsoc + \def\@oddfoot{\hss\normalfont\scriptsize\raisebox{-1.5\@IEEEnormalsizeunitybaselineskip}[0ex][0ex]{\@IEEEpubid}\hss}% + \def\@evenfoot{\hss\normalfont\scriptsize\raisebox{-1.5\@IEEEnormalsizeunitybaselineskip}[0ex][0ex]{\@IEEEpubid}\hss}% + \else + \def\@oddfoot{\hss\normalfont\footnotesize\raisebox{1.5ex}[1.5ex]{\@IEEEpubid}\hss}% + \def\@evenfoot{\hss\normalfont\footnotesize\raisebox{1.5ex}[1.5ex]{\@IEEEpubid}\hss}% + \fi + \fi + \fi +\fi} + + +% peer review cover page style +\def\ps@IEEEpeerreviewcoverpagestyle{% +\def\@oddhead{}\def\@evenhead{}% +\def\@oddfoot{}\def\@evenfoot{}% +\ifCLASSOPTIONdraftcls + \ifCLASSOPTIONdraftclsnofoot\else + \def\@oddfoot{\scriptsize \@date\hfil DRAFT}% + \def\@evenfoot{\scriptsize DRAFT\hfil \@date}% + \fi +\else + % non-draft mode footers + \if@IEEEusingpubid + \footskip 0pt% + \ifCLASSOPTIONcompsoc + \def\@oddfoot{\hss\normalfont\scriptsize\raisebox{-1.5\@IEEEnormalsizeunitybaselineskip}[0ex][0ex]{\@IEEEpubid}\hss}% + \def\@evenfoot{\hss\normalfont\scriptsize\raisebox{-1.5\@IEEEnormalsizeunitybaselineskip}[0ex][0ex]{\@IEEEpubid}\hss}% + \else + \def\@oddfoot{\hss\normalfont\footnotesize\raisebox{1.5ex}[1.5ex]{\@IEEEpubid}\hss}% + \def\@evenfoot{\hss\normalfont\footnotesize\raisebox{1.5ex}[1.5ex]{\@IEEEpubid}\hss}% + \fi + \fi +\fi} + + +% start with empty headings +\def\rightmark{}\def\leftmark{} + + +%% Defines the command for putting the header. \footernote{TEXT} is the same +%% as \markboth{TEXT}{TEXT}. +%% Note that all the text is forced into uppercase, if you have some text +%% that needs to be in lower case, for instance et. al., then either manually +%% set \leftmark and \rightmark or use \MakeLowercase{et. al.} within the +%% arguments to \markboth. +\def\markboth#1#2{\def\leftmark{\@IEEEcompsoconly{\sffamily}\MakeUppercase{#1}}% +\def\rightmark{\@IEEEcompsoconly{\sffamily}\MakeUppercase{#2}}} +\def\footernote#1{\markboth{#1}{#1}} + +\def\today{\ifcase\month\or + January\or February\or March\or April\or May\or June\or + July\or August\or September\or October\or November\or December\fi + \space\number\day, \number\year} + + + + +%% CITATION AND BIBLIOGRAPHY COMMANDS +%% +%% V1.6 no longer supports the older, nonstandard \shortcite and \citename setup stuff +% +% +% Modify Latex2e \@citex to separate citations with "], [" +\def\@citex[#1]#2{% + \let\@citea\@empty + \@cite{\@for\@citeb:=#2\do + {\@citea\def\@citea{], [}% + \edef\@citeb{\expandafter\@firstofone\@citeb\@empty}% + \if@filesw\immediate\write\@auxout{\string\citation{\@citeb}}\fi + \@ifundefined{b@\@citeb}{\mbox{\reset@font\bfseries ?}% + \G@refundefinedtrue + \@latex@warning + {Citation `\@citeb' on page \thepage \space undefined}}% + {\hbox{\csname b@\@citeb\endcsname}}}}{#1}} + +% V1.6 we create hooks for the optional use of Donald Arseneau's +% cite.sty package. cite.sty is "smart" and will notice that the +% following format controls are already defined and will not +% redefine them. The result will be the proper sorting of the +% citation numbers and auto detection of 3 or more entry "ranges" - +% all in IEEE style: [1], [2], [5]--[7], [12] +% This also allows for an optional note, i.e., \cite[mynote]{..}. +% If the \cite with note has more than one reference, the note will +% be applied to the last of the listed references. It is generally +% desired that if a note is given, only one reference is listed in +% that \cite. +% Thanks to Mr. Arseneau for providing the required format arguments +% to produce the IEEE style. +\def\citepunct{], [} +\def\citedash{]--[} + +% V1.7 default to using same font for urls made by url.sty +\AtBeginDocument{\csname url@samestyle\endcsname} + +% V1.6 class files should always provide these +\def\newblock{\hskip .11em\@plus.33em\@minus.07em} +\let\@openbib@code\@empty + + +% Provide support for the control entries of IEEEtran.bst V1.00 and later. +% V1.7 optional argument allows for a different aux file to be specified in +% order to handle multiple bibliographies. For example, with multibib.sty: +% \newcites{sec}{Secondary Literature} +% \bstctlcite[@auxoutsec]{BSTcontrolhak} +\def\bstctlcite{\@ifnextchar[{\@bstctlcite}{\@bstctlcite[@auxout]}} +\def\@bstctlcite[#1]#2{\@bsphack + \@for\@citeb:=#2\do{% + \edef\@citeb{\expandafter\@firstofone\@citeb}% + \if@filesw\immediate\write\csname #1\endcsname{\string\citation{\@citeb}}\fi}% + \@esphack} + +% V1.6 provide a way for a user to execute a command just before +% a given reference number - used to insert a \newpage to balance +% the columns on the last page +\edef\@IEEEtriggerrefnum{0} % the default of zero means that + % the command is not executed +\def\@IEEEtriggercmd{\newpage} + +% allow the user to alter the triggered command +\long\def\IEEEtriggercmd#1{\long\def\@IEEEtriggercmd{#1}} + +% allow user a way to specify the reference number just before the +% command is executed +\def\IEEEtriggeratref#1{\@IEEEtrantmpcountA=#1% +\edef\@IEEEtriggerrefnum{\the\@IEEEtrantmpcountA}}% + +% trigger command at the given reference +\def\@IEEEbibitemprefix{\@IEEEtrantmpcountA=\@IEEEtriggerrefnum\relax% +\advance\@IEEEtrantmpcountA by -1\relax% +\ifnum\c@enumiv=\@IEEEtrantmpcountA\relax\@IEEEtriggercmd\relax\fi} + + +\def\@biblabel#1{[#1]} + +% compsoc journals left align the reference numbers +\@IEEEcompsocnotconfonly{\def\@biblabel#1{[#1]\hfill}} + +% controls bib item spacing +\def\IEEEbibitemsep{0pt plus .5pt} + +\@IEEEcompsocconfonly{\def\IEEEbibitemsep{1\baselineskip plus 0.25\baselineskip minus 0.25\baselineskip}} + + +\def\thebibliography#1{\section*{\refname}% + \addcontentsline{toc}{section}{\refname}% + % V1.6 add some rubber space here and provide a command trigger + \footnotesize\@IEEEcompsocconfonly{\small}\vskip 0.3\baselineskip plus 0.1\baselineskip minus 0.1\baselineskip% + \list{\@biblabel{\@arabic\c@enumiv}}% + {\settowidth\labelwidth{\@biblabel{#1}}% + \leftmargin\labelwidth + \advance\leftmargin\labelsep\relax + \itemsep \IEEEbibitemsep\relax + \usecounter{enumiv}% + \let\p@enumiv\@empty + \renewcommand\theenumiv{\@arabic\c@enumiv}}% + \let\@IEEElatexbibitem\bibitem% + \def\bibitem{\@IEEEbibitemprefix\@IEEElatexbibitem}% +\def\newblock{\hskip .11em plus .33em minus .07em}% +% originally: +% \sloppy\clubpenalty4000\widowpenalty4000% +% by adding the \interlinepenalty here, we make it more +% difficult, but not impossible, for LaTeX to break within a reference. +% IEEE almost never breaks a reference (but they do it more often with +% technotes). You may get an underfull vbox warning around the bibliography, +% but the final result will be much more like what IEEE will publish. +% MDS 11/2000 +\ifCLASSOPTIONtechnote\sloppy\clubpenalty4000\widowpenalty4000\interlinepenalty100% +\else\sloppy\clubpenalty4000\widowpenalty4000\interlinepenalty500\fi% + \sfcode`\.=1000\relax} +\let\endthebibliography=\endlist + + + + +% TITLE PAGE COMMANDS +% +% +% \IEEEmembership is used to produce the sublargesize italic font used to indicate author +% IEEE membership. compsoc uses a large size sans slant font +\def\IEEEmembership#1{{\@IEEEnotcompsoconly{\sublargesize}\normalfont\@IEEEcompsoconly{\sffamily}\textit{#1}}} + + +% \IEEEauthorrefmark{} produces a footnote type symbol to indicate author affiliation. +% When given an argument of 1 to 9, \IEEEauthorrefmark{} follows the standard LaTeX footnote +% symbol sequence convention. However, for arguments 10 and above, \IEEEauthorrefmark{} +% reverts to using lower case roman numerals, so it cannot overflow. Do note that you +% cannot use \footnotemark[] in place of \IEEEauthorrefmark{} within \author as the footnote +% symbols will have been turned off to prevent \thanks from creating footnote marks. +% \IEEEauthorrefmark{} produces a symbol that appears to LaTeX as having zero vertical +% height - this allows for a more compact line packing, but the user must ensure that +% the interline spacing is large enough to prevent \IEEEauthorrefmark{} from colliding +% with the text above. +% V1.7 make this a robust command +\DeclareRobustCommand*{\IEEEauthorrefmark}[1]{\raisebox{0pt}[0pt][0pt]{\textsuperscript{\footnotesize\ensuremath{\ifcase#1\or *\or \dagger\or \ddagger\or% + \mathsection\or \mathparagraph\or \|\or **\or \dagger\dagger% + \or \ddagger\ddagger \else\textsuperscript{\expandafter\romannumeral#1}\fi}}}} + + +% FONT CONTROLS AND SPACINGS FOR CONFERENCE MODE AUTHOR NAME AND AFFILIATION BLOCKS +% +% The default font styles for the author name and affiliation blocks (confmode) +\def\@IEEEauthorblockNstyle{\normalfont\@IEEEcompsocnotconfonly{\sffamily}\sublargesize\@IEEEcompsocconfonly{\large}} +\def\@IEEEauthorblockAstyle{\normalfont\@IEEEcompsocnotconfonly{\sffamily}\@IEEEcompsocconfonly{\itshape}\normalsize\@IEEEcompsocconfonly{\large}} +% The default if the user does not use an author block +\def\@IEEEauthordefaulttextstyle{\normalfont\@IEEEcompsocnotconfonly{\sffamily}\sublargesize} + +% spacing from title (or special paper notice) to author name blocks (confmode) +% can be negative +\def\@IEEEauthorblockconfadjspace{-0.25em} +% compsoc conferences need more space here +\@IEEEcompsocconfonly{\def\@IEEEauthorblockconfadjspace{0.75\@IEEEnormalsizeunitybaselineskip}} + +% spacing between name and affiliation blocks (confmode) +% This can be negative. +% IEEE doesn't want any added spacing here, but I will leave these +% controls in place in case they ever change their mind. +% Personally, I like 0.75ex. +%\def\@IEEEauthorblockNtopspace{0.75ex} +%\def\@IEEEauthorblockAtopspace{0.75ex} +\def\@IEEEauthorblockNtopspace{0.0ex} +\def\@IEEEauthorblockAtopspace{0.0ex} +% baseline spacing within name and affiliation blocks (confmode) +% must be positive, spacings below certain values will make +% the position of line of text sensitive to the contents of the +% line above it i.e., whether or not the prior line has descenders, +% subscripts, etc. For this reason it is a good idea to keep +% these above 2.6ex +\def\@IEEEauthorblockNinterlinespace{2.6ex} +\def\@IEEEauthorblockAinterlinespace{2.75ex} + +% This tracks the required strut size. +% See the \@IEEEauthorhalign command for the actual default value used. +\def\@IEEEauthorblockXinterlinespace{2.7ex} + +% variables to retain font size and style across groups +% values given here have no effect as they will be overwritten later +\gdef\@IEEESAVESTATEfontsize{10} +\gdef\@IEEESAVESTATEfontbaselineskip{12} +\gdef\@IEEESAVESTATEfontencoding{OT1} +\gdef\@IEEESAVESTATEfontfamily{ptm} +\gdef\@IEEESAVESTATEfontseries{m} +\gdef\@IEEESAVESTATEfontshape{n} + +% saves the current font attributes +\def\@IEEEcurfontSAVE{\global\let\@IEEESAVESTATEfontsize\f@size% +\global\let\@IEEESAVESTATEfontbaselineskip\f@baselineskip% +\global\let\@IEEESAVESTATEfontencoding\f@encoding% +\global\let\@IEEESAVESTATEfontfamily\f@family% +\global\let\@IEEESAVESTATEfontseries\f@series% +\global\let\@IEEESAVESTATEfontshape\f@shape} + +% restores the saved font attributes +\def\@IEEEcurfontRESTORE{\fontsize{\@IEEESAVESTATEfontsize}{\@IEEESAVESTATEfontbaselineskip}% +\fontencoding{\@IEEESAVESTATEfontencoding}% +\fontfamily{\@IEEESAVESTATEfontfamily}% +\fontseries{\@IEEESAVESTATEfontseries}% +\fontshape{\@IEEESAVESTATEfontshape}% +\selectfont} + + +% variable to indicate if the current block is the first block in the column +\newif\if@IEEEprevauthorblockincol \@IEEEprevauthorblockincolfalse + + +% the command places a strut with height and depth = \@IEEEauthorblockXinterlinespace +% we use this technique to have complete manual control over the spacing of the lines +% within the halign environment. +% We set the below baseline portion at 30%, the above +% baseline portion at 70% of the total length. +% Responds to changes in the document's \baselinestretch +\def\@IEEEauthorstrutrule{\@IEEEtrantmpdimenA\@IEEEauthorblockXinterlinespace% +\@IEEEtrantmpdimenA=\baselinestretch\@IEEEtrantmpdimenA% +\rule[-0.3\@IEEEtrantmpdimenA]{0pt}{\@IEEEtrantmpdimenA}} + + +% blocks to hold the authors' names and affilations. +% Makes formatting easy for conferences +% +% use real definitions in conference mode +% name block +\def\IEEEauthorblockN#1{\relax\@IEEEauthorblockNstyle% set the default text style +\gdef\@IEEEauthorblockXinterlinespace{0pt}% disable strut for spacer row +% the \expandafter hides the \cr in conditional tex, see the array.sty docs +% for details, probably not needed here as the \cr is in a macro +% do a spacer row if needed +\if@IEEEprevauthorblockincol\expandafter\@IEEEauthorblockNtopspaceline\fi +\global\@IEEEprevauthorblockincoltrue% we now have a block in this column +%restore the correct strut value +\gdef\@IEEEauthorblockXinterlinespace{\@IEEEauthorblockNinterlinespace}% +% input the author names +#1% +% end the row if the user did not already +\crcr} +% spacer row for names +\def\@IEEEauthorblockNtopspaceline{\cr\noalign{\vskip\@IEEEauthorblockNtopspace}} +% +% affiliation block +\def\IEEEauthorblockA#1{\relax\@IEEEauthorblockAstyle% set the default text style +\gdef\@IEEEauthorblockXinterlinespace{0pt}%disable strut for spacer row +% the \expandafter hides the \cr in conditional tex, see the array.sty docs +% for details, probably not needed here as the \cr is in a macro +% do a spacer row if needed +\if@IEEEprevauthorblockincol\expandafter\@IEEEauthorblockAtopspaceline\fi +\global\@IEEEprevauthorblockincoltrue% we now have a block in this column +%restore the correct strut value +\gdef\@IEEEauthorblockXinterlinespace{\@IEEEauthorblockAinterlinespace}% +% input the author affiliations +#1% +% end the row if the user did not already +\crcr} +% spacer row for affiliations +\def\@IEEEauthorblockAtopspaceline{\cr\noalign{\vskip\@IEEEauthorblockAtopspace}} + + +% allow papers to compile even if author blocks are used in modes other +% than conference or peerreviewca. For such cases, we provide dummy blocks. +\ifCLASSOPTIONconference +\else + \ifCLASSOPTIONpeerreviewca\else + % not conference or peerreviewca mode + \def\IEEEauthorblockN#1{#1}% + \def\IEEEauthorblockA#1{#1}% + \fi +\fi + + + +% we provide our own halign so as not to have to depend on tabular +\def\@IEEEauthorhalign{\@IEEEauthordefaulttextstyle% default text style + \lineskip=0pt\relax% disable line spacing + \lineskiplimit=0pt\relax% + \baselineskip=0pt\relax% + \@IEEEcurfontSAVE% save the current font + \mathsurround\z@\relax% no extra spacing around math + \let\\\@IEEEauthorhaligncr% replace newline with halign friendly one + \tabskip=0pt\relax% no column spacing + \everycr{}% ensure no problems here + \@IEEEprevauthorblockincolfalse% no author blocks yet + \def\@IEEEauthorblockXinterlinespace{2.7ex}% default interline space + \vtop\bgroup%vtop box + \halign\bgroup&\relax\hfil\@IEEEcurfontRESTORE\relax ##\relax + \hfil\@IEEEcurfontSAVE\@IEEEauthorstrutrule\cr} + +% ensure last line, exit from halign, close vbox +\def\end@IEEEauthorhalign{\crcr\egroup\egroup} + +% handle bogus star form +\def\@IEEEauthorhaligncr{{\ifnum0=`}\fi\@ifstar{\@@IEEEauthorhaligncr}{\@@IEEEauthorhaligncr}} + +% test and setup the optional argument to \\[] +\def\@@IEEEauthorhaligncr{\@testopt\@@@IEEEauthorhaligncr\z@skip} + +% end the line and do the optional spacer +\def\@@@IEEEauthorhaligncr[#1]{\ifnum0=`{\fi}\cr\noalign{\vskip#1\relax}} + + + +% flag to prevent multiple \and warning messages +\newif\if@IEEEWARNand +\@IEEEWARNandtrue + +% if in conference or peerreviewca modes, we support the use of \and as \author is a +% tabular environment, otherwise we warn the user that \and is invalid +% outside of conference or peerreviewca modes. +\def\and{\relax} % provide a bogus \and that we will then override + +\renewcommand{\and}[1][\relax]{\if@IEEEWARNand\typeout{** WARNING: \noexpand\and is valid only + when in conference or peerreviewca}\typeout{modes (line \the\inputlineno).}\fi\global\@IEEEWARNandfalse} + +\ifCLASSOPTIONconference% +\renewcommand{\and}[1][\hfill]{\end{@IEEEauthorhalign}#1\begin{@IEEEauthorhalign}}% +\fi +\ifCLASSOPTIONpeerreviewca +\renewcommand{\and}[1][\hfill]{\end{@IEEEauthorhalign}#1\begin{@IEEEauthorhalign}}% +\fi + + +% page clearing command +% based on LaTeX2e's \cleardoublepage, but allows different page styles +% for the inserted blank pages +\def\@IEEEcleardoublepage#1{\clearpage\if@twoside\ifodd\c@page\else +\hbox{}\thispagestyle{#1}\newpage\if@twocolumn\hbox{}\thispagestyle{#1}\newpage\fi\fi\fi} + + +% user command to invoke the title page +\def\maketitle{\par% + \begingroup% + \normalfont% + \def\thefootnote{}% the \thanks{} mark type is empty + \def\footnotemark{}% and kill space from \thanks within author + \let\@makefnmark\relax% V1.7, must *really* kill footnotemark to remove all \textsuperscript spacing as well. + \footnotesize% equal spacing between thanks lines + \footnotesep 0.7\baselineskip%see global setting of \footnotesep for more info + % V1.7 disable \thanks note indention for compsoc + \@IEEEcompsoconly{\long\def\@makefntext##1{\parindent 1em\noindent\hbox{\@makefnmark}##1}}% + \normalsize% + \ifCLASSOPTIONpeerreview + \newpage\global\@topnum\z@ \@maketitle\@IEEEstatictitlevskip\@IEEEaftertitletext% + \thispagestyle{IEEEpeerreviewcoverpagestyle}\@thanks% + \else + \if@twocolumn% + \ifCLASSOPTIONtechnote% + \newpage\global\@topnum\z@ \@maketitle\@IEEEstatictitlevskip\@IEEEaftertitletext% + \else + \twocolumn[\@maketitle\@IEEEdynamictitlevspace\@IEEEaftertitletext]% + \fi + \else + \newpage\global\@topnum\z@ \@maketitle\@IEEEstatictitlevskip\@IEEEaftertitletext% + \fi + \thispagestyle{IEEEtitlepagestyle}\@thanks% + \fi + % pullup page for pubid if used. + \if@IEEEusingpubid + \enlargethispage{-\@IEEEpubidpullup}% + \fi + \endgroup + \setcounter{footnote}{0}\let\maketitle\relax\let\@maketitle\relax + \gdef\@thanks{}% + % v1.6b do not clear these as we will need the title again for peer review papers + % \gdef\@author{}\gdef\@title{}% + \let\thanks\relax} + + + +% V1.7 parbox to format \@IEEEcompsoctitleabstractindextext +\long\def\@IEEEcompsoctitleabstractindextextbox#1{\parbox{0.915\textwidth}{#1}} + +% formats the Title, authors names, affiliations and special paper notice +% THIS IS A CONTROLLED SPACING COMMAND! Do not allow blank lines or unintentional +% spaces to enter the definition - use % at the end of each line +\def\@maketitle{\newpage +\begin{center}% +\ifCLASSOPTIONtechnote% technotes + {\bfseries\large\@IEEEcompsoconly{\sffamily}\@title\par}\vskip 1.3em{\lineskip .5em\@IEEEcompsoconly{\sffamily}\@author + \@IEEEspecialpapernotice\par{\@IEEEcompsoconly{\vskip 1.5em\relax + \@IEEEcompsoctitleabstractindextextbox{\@IEEEcompsoctitleabstractindextext}\par + \hfill\@IEEEcompsocdiamondline\hfill\hbox{}\par}}}\relax +\else% not a technote + \vskip0.2em{\Huge\@IEEEcompsoconly{\sffamily}\@IEEEcompsocconfonly{\normalfont\normalsize\vskip 2\@IEEEnormalsizeunitybaselineskip + \bfseries\Large}\@title\par}\vskip1.0em\par% + % V1.6 handle \author differently if in conference mode + \ifCLASSOPTIONconference% + {\@IEEEspecialpapernotice\mbox{}\vskip\@IEEEauthorblockconfadjspace% + \mbox{}\hfill\begin{@IEEEauthorhalign}\@author\end{@IEEEauthorhalign}\hfill\mbox{}\par}\relax + \else% peerreviewca, peerreview or journal + \ifCLASSOPTIONpeerreviewca + % peerreviewca handles author names just like conference mode + {\@IEEEcompsoconly{\sffamily}\@IEEEspecialpapernotice\mbox{}\vskip\@IEEEauthorblockconfadjspace% + \mbox{}\hfill\begin{@IEEEauthorhalign}\@author\end{@IEEEauthorhalign}\hfill\mbox{}\par + {\@IEEEcompsoconly{\vskip 1.5em\relax + \@IEEEcompsoctitleabstractindextextbox{\@IEEEcompsoctitleabstractindextext}\par\hfill + \@IEEEcompsocdiamondline\hfill\hbox{}\par}}}\relax + \else% journal or peerreview + {\lineskip.5em\@IEEEcompsoconly{\sffamily}\sublargesize\@author\@IEEEspecialpapernotice\par + {\@IEEEcompsoconly{\vskip 1.5em\relax + \@IEEEcompsoctitleabstractindextextbox{\@IEEEcompsoctitleabstractindextext}\par\hfill + \@IEEEcompsocdiamondline\hfill\hbox{}\par}}}\relax + \fi + \fi +\fi\end{center}} + + + +% V1.7 Computer Society "diamond line" which follows index terms for nonconference papers +\def\@IEEEcompsocdiamondline{\vrule depth 0pt height 0.5pt width 4cm\hspace{7.5pt}% +\raisebox{-3.5pt}{\fontfamily{pzd}\fontencoding{U}\fontseries{m}\fontshape{n}\fontsize{11}{12}\selectfont\char70}% +\hspace{7.5pt}\vrule depth 0pt height 0.5pt width 4cm\relax} + +% V1.7 standard LateX2e \thanks, but with \itshape under compsoc. Also make it a \long\def +% We also need to trigger the one-shot footnote rule +\def\@IEEEtriggeroneshotfootnoterule{\global\@IEEEenableoneshotfootnoteruletrue} + + +\long\def\thanks#1{\footnotemark + \protected@xdef\@thanks{\@thanks + \protect\footnotetext[\the\c@footnote]{\@IEEEcompsoconly{\itshape + \protect\@IEEEtriggeroneshotfootnoterule\relax}\ignorespaces#1}}} +\let\@thanks\@empty + +% V1.7 allow \author to contain \par's. This is needed to allow \thanks to contain \par. +\long\def\author#1{\gdef\@author{#1}} + + +% in addition to setting up IEEEitemize, we need to remove a baselineskip space above and +% below it because \list's \pars introduce blank lines because of the footnote struts. +\def\@IEEEsetupcompsocitemizelist{\def\labelitemi{$\bullet$}% +\setlength{\IEEElabelindent}{0pt}\setlength{\parskip}{0pt}% +\setlength{\partopsep}{0pt}\setlength{\topsep}{0.5\baselineskip}\vspace{-1\baselineskip}\relax} + + +% flag for fake non-compsoc \IEEEcompsocthanksitem - prevents line break on very first item +\newif\if@IEEEbreakcompsocthanksitem \@IEEEbreakcompsocthanksitemfalse + +\ifCLASSOPTIONcompsoc +% V1.7 compsoc bullet item \thanks +% also, we need to redefine this to destroy the argument in \@IEEEdynamictitlevspace +\long\def\IEEEcompsocitemizethanks#1{\relax\@IEEEbreakcompsocthanksitemfalse\footnotemark + \protected@xdef\@thanks{\@thanks + \protect\footnotetext[\the\c@footnote]{\itshape\protect\@IEEEtriggeroneshotfootnoterule + {\let\IEEEiedlistdecl\relax\protect\begin{IEEEitemize}[\protect\@IEEEsetupcompsocitemizelist]\ignorespaces#1\relax + \protect\end{IEEEitemize}}\protect\vspace{-1\baselineskip}}}} +\DeclareRobustCommand*{\IEEEcompsocthanksitem}{\item} +\else +% non-compsoc, allow for dual compilation via rerouting to normal \thanks +\long\def\IEEEcompsocitemizethanks#1{\thanks{#1}} +% redirect to "pseudo-par" \hfil\break\indent after swallowing [] from \IEEEcompsocthanksitem[] +\DeclareRobustCommand{\IEEEcompsocthanksitem}{\@ifnextchar [{\@IEEEthanksswallowoptionalarg}% +{\@IEEEthanksswallowoptionalarg[\relax]}} +% be sure and break only after first item, be sure and ignore spaces after optional argument +\def\@IEEEthanksswallowoptionalarg[#1]{\relax\if@IEEEbreakcompsocthanksitem\hfil\break +\indent\fi\@IEEEbreakcompsocthanksitemtrue\ignorespaces} +\fi + + +% V1.6b define the \IEEEpeerreviewmaketitle as needed +\ifCLASSOPTIONpeerreview +\def\IEEEpeerreviewmaketitle{\@IEEEcleardoublepage{empty}% +\ifCLASSOPTIONtwocolumn +\twocolumn[\@IEEEpeerreviewmaketitle\@IEEEdynamictitlevspace] +\else +\newpage\@IEEEpeerreviewmaketitle\@IEEEstatictitlevskip +\fi +\thispagestyle{IEEEtitlepagestyle}} +\else +% \IEEEpeerreviewmaketitle does nothing if peer review option has not been selected +\def\IEEEpeerreviewmaketitle{\relax} +\fi + +% peerreview formats the repeated title like the title in journal papers. +\def\@IEEEpeerreviewmaketitle{\begin{center}\@IEEEcompsoconly{\sffamily}% +\normalfont\normalsize\vskip0.2em{\Huge\@title\par}\vskip1.0em\par +\end{center}} + + + +% V1.6 +% this is a static rubber spacer between the title/authors and the main text +% used for single column text, or when the title appears in the first column +% of two column text (technotes). +\def\@IEEEstatictitlevskip{{\normalfont\normalsize +% adjust spacing to next text +% v1.6b handle peer review papers +\ifCLASSOPTIONpeerreview +% for peer review papers, the same value is used for both title pages +% regardless of the other paper modes + \vskip 1\baselineskip plus 0.375\baselineskip minus 0.1875\baselineskip +\else + \ifCLASSOPTIONconference% conference + \vskip 1\baselineskip plus 0.375\baselineskip minus 0.1875\baselineskip% + \else% + \ifCLASSOPTIONtechnote% technote + \vskip 1\baselineskip plus 0.375\baselineskip minus 0.1875\baselineskip% + \else% journal uses more space + \vskip 2.5\baselineskip plus 0.75\baselineskip minus 0.375\baselineskip% + \fi + \fi +\fi}} + + +% V1.6 +% This is a dynamically determined rigid spacer between the title/authors +% and the main text. This is used only for single column titles over two +% column text (most common) +% This is bit tricky because we have to ensure that the textheight of the +% main text is an integer multiple of \baselineskip +% otherwise underfull vbox problems may develop in the second column of the +% text on the titlepage +% The possible use of \IEEEpubid must also be taken into account. +\def\@IEEEdynamictitlevspace{{% + % we run within a group so that all the macros can be forgotten when we are done + \long\def\thanks##1{\relax}%don't allow \thanks to run when we evaluate the vbox height + \long\def\IEEEcompsocitemizethanks##1{\relax}%don't allow \IEEEcompsocitemizethanks to run when we evaluate the vbox height + \normalfont\normalsize% we declare more descriptive variable names + \let\@IEEEmaintextheight=\@IEEEtrantmpdimenA%height of the main text columns + \let\@IEEEINTmaintextheight=\@IEEEtrantmpdimenB%height of the main text columns with integer # lines + % set the nominal and minimum values for the title spacer + % the dynamic algorithm will not allow the spacer size to + % become less than \@IEEEMINtitlevspace - instead it will be + % lengthened + % default to journal values + \def\@IEEENORMtitlevspace{2.5\baselineskip}% + \def\@IEEEMINtitlevspace{2\baselineskip}% + % conferences and technotes need tighter spacing + \ifCLASSOPTIONconference%conference + \def\@IEEENORMtitlevspace{1\baselineskip}% + \def\@IEEEMINtitlevspace{0.75\baselineskip}% + \fi + \ifCLASSOPTIONtechnote%technote + \def\@IEEENORMtitlevspace{1\baselineskip}% + \def\@IEEEMINtitlevspace{0.75\baselineskip}% + \fi% + % get the height that the title will take up + \ifCLASSOPTIONpeerreview + \settoheight{\@IEEEmaintextheight}{\vbox{\hsize\textwidth \@IEEEpeerreviewmaketitle}}% + \else + \settoheight{\@IEEEmaintextheight}{\vbox{\hsize\textwidth \@maketitle}}% + \fi + \@IEEEmaintextheight=-\@IEEEmaintextheight% title takes away from maintext, so reverse sign + % add the height of the page textheight + \advance\@IEEEmaintextheight by \textheight% + % correct for title pages using pubid + \ifCLASSOPTIONpeerreview\else + % peerreview papers use the pubid on the cover page only. + % And the cover page uses a static spacer. + \if@IEEEusingpubid\advance\@IEEEmaintextheight by -\@IEEEpubidpullup\fi + \fi% + % subtract off the nominal value of the title bottom spacer + \advance\@IEEEmaintextheight by -\@IEEENORMtitlevspace% + % \topskip takes away some too + \advance\@IEEEmaintextheight by -\topskip% + % calculate the column height of the main text for lines + % now we calculate the main text height as if holding + % an integer number of \normalsize lines after the first + % and discard any excess fractional remainder + % we subtracted the first line, because the first line + % is placed \topskip into the maintext, not \baselineskip like the + % rest of the lines. + \@IEEEINTmaintextheight=\@IEEEmaintextheight% + \divide\@IEEEINTmaintextheight by \baselineskip% + \multiply\@IEEEINTmaintextheight by \baselineskip% + % now we calculate how much the title spacer height will + % have to be reduced from nominal (\@IEEEREDUCEmaintextheight is always + % a positive value) so that the maintext area will contain an integer + % number of normal size lines + % we change variable names here (to avoid confusion) as we no longer + % need \@IEEEINTmaintextheight and can reuse its dimen register + \let\@IEEEREDUCEmaintextheight=\@IEEEINTmaintextheight% + \advance\@IEEEREDUCEmaintextheight by -\@IEEEmaintextheight% + \advance\@IEEEREDUCEmaintextheight by \baselineskip% + % this is the calculated height of the spacer + % we change variable names here (to avoid confusion) as we no longer + % need \@IEEEmaintextheight and can reuse its dimen register + \let\@IEEECOMPENSATElen=\@IEEEmaintextheight% + \@IEEECOMPENSATElen=\@IEEENORMtitlevspace% set the nominal value + % we go with the reduced length if it is smaller than an increase + \ifdim\@IEEEREDUCEmaintextheight < 0.5\baselineskip\relax% + \advance\@IEEECOMPENSATElen by -\@IEEEREDUCEmaintextheight% + % if the resulting spacer is too small back out and go with an increase instead + \ifdim\@IEEECOMPENSATElen<\@IEEEMINtitlevspace\relax% + \advance\@IEEECOMPENSATElen by \baselineskip% + \fi% + \else% + % go with an increase because it is closer to the nominal than a decrease + \advance\@IEEECOMPENSATElen by -\@IEEEREDUCEmaintextheight% + \advance\@IEEECOMPENSATElen by \baselineskip% + \fi% + % set the calculated rigid spacer + \vspace{\@IEEECOMPENSATElen}}} + + + +% V1.6 +% we allow the user access to the last part of the title area +% useful in emergencies such as when a different spacing is needed +% This text is NOT compensated for in the dynamic sizer. +\let\@IEEEaftertitletext=\relax +\long\def\IEEEaftertitletext#1{\def\@IEEEaftertitletext{#1}} + +% V1.7 provide a way for users to enter abstract and keywords +% into the onecolumn title are. This text is compensated for +% in the dynamic sizer. +\let\@IEEEcompsoctitleabstractindextext=\relax +\long\def\IEEEcompsoctitleabstractindextext#1{\def\@IEEEcompsoctitleabstractindextext{#1}} +% V1.7 provide a way for users to get the \@IEEEcompsoctitleabstractindextext if +% not in compsoc journal mode - this way abstract and keywords can be placed +% in their conventional position if not in compsoc mode. +\def\IEEEdisplaynotcompsoctitleabstractindextext{% +\ifCLASSOPTIONcompsoc% display if compsoc conf +\ifCLASSOPTIONconference\@IEEEcompsoctitleabstractindextext\fi +\else% or if not compsoc +\@IEEEcompsoctitleabstractindextext\fi} + + +% command to allow alteration of baselinestretch, but only if the current +% baselineskip is unity. Used to tweak the compsoc abstract and keywords line spacing. +\def\@IEEEtweakunitybaselinestretch#1{{\def\baselinestretch{1}\selectfont +\global\@tempskipa\baselineskip}\ifnum\@tempskipa=\baselineskip% +\def\baselinestretch{#1}\selectfont\fi\relax} + + +% abstract and keywords are in \small, except +% for 9pt docs in which they are in \footnotesize +% Because 9pt docs use an 8pt footnotesize, \small +% becomes a rather awkward 8.5pt +\def\@IEEEabskeysecsize{\small} +\ifx\CLASSOPTIONpt\@IEEEptsizenine + \def\@IEEEabskeysecsize{\footnotesize} +\fi + +% compsoc journals use \footnotesize, compsoc conferences use normalsize +\@IEEEcompsoconly{\def\@IEEEabskeysecsize{\footnotesize}} +\@IEEEcompsocconfonly{\def\@IEEEabskeysecsize{\normalsize}} + + + + +% V1.6 have abstract and keywords strip leading spaces, pars and newlines +% so that spacing is more tightly controlled. +\def\abstract{\normalfont + \if@twocolumn + \@IEEEabskeysecsize\bfseries\textit{\abstractname}---\relax + \else + \begin{center}\vspace{-1.78ex}\@IEEEabskeysecsize\textbf{\abstractname}\end{center}\quotation\@IEEEabskeysecsize + \fi\@IEEEgobbleleadPARNLSP} +% V1.6 IEEE wants only 1 pica from end of abstract to introduction heading when in +% conference mode (the heading already has this much above it) +\def\endabstract{\relax\ifCLASSOPTIONconference\vspace{0ex}\else\vspace{1.34ex}\fi\par\if@twocolumn\else\endquotation\fi + \normalfont\normalsize} + +\def\IEEEkeywords{\normalfont + \if@twocolumn + \@IEEEabskeysecsize\bfseries\textit{\IEEEkeywordsname}---\relax + \else + \begin{center}\@IEEEabskeysecsize\textbf{\IEEEkeywordsname}\end{center}\quotation\@IEEEabskeysecsize + \fi\@IEEEgobbleleadPARNLSP} +\def\endIEEEkeywords{\relax\ifCLASSOPTIONtechnote\vspace{1.34ex}\else\vspace{0.67ex}\fi + \par\if@twocolumn\else\endquotation\fi% + \normalfont\normalsize} + +% V1.7 compsoc keywords index terms +\ifCLASSOPTIONcompsoc + \ifCLASSOPTIONconference% compsoc conference +\def\abstract{\normalfont + \begin{center}\@IEEEabskeysecsize\textbf{\large\abstractname}\end{center}\vskip 0.5\baselineskip plus 0.1\baselineskip minus 0.1\baselineskip + \if@twocolumn\else\quotation\fi\itshape\@IEEEabskeysecsize% + \par\@IEEEgobbleleadPARNLSP} +\def\IEEEkeywords{\normalfont\vskip 1.5\baselineskip plus 0.25\baselineskip minus 0.25\baselineskip + \begin{center}\@IEEEabskeysecsize\textbf{\large\IEEEkeywordsname}\end{center}\vskip 0.5\baselineskip plus 0.1\baselineskip minus 0.1\baselineskip + \if@twocolumn\else\quotation\fi\itshape\@IEEEabskeysecsize% + \par\@IEEEgobbleleadPARNLSP} + \else% compsoc not conference +\def\abstract{\normalfont\@IEEEtweakunitybaselinestretch{1.15}\sffamily + \if@twocolumn + \@IEEEabskeysecsize\noindent\textbf{\abstractname}---\relax + \else + \begin{center}\vspace{-1.78ex}\@IEEEabskeysecsize\textbf{\abstractname}\end{center}\quotation\@IEEEabskeysecsize% + \fi\@IEEEgobbleleadPARNLSP} +\def\IEEEkeywords{\normalfont\@IEEEtweakunitybaselinestretch{1.15}\sffamily + \if@twocolumn + \@IEEEabskeysecsize\vskip 0.5\baselineskip plus 0.25\baselineskip minus 0.25\baselineskip\noindent + \textbf{\IEEEkeywordsname}---\relax + \else + \begin{center}\@IEEEabskeysecsize\textbf{\IEEEkeywordsname}\end{center}\quotation\@IEEEabskeysecsize% + \fi\@IEEEgobbleleadPARNLSP} + \fi +\fi + + + +% gobbles all leading \, \\ and \par, upon finding first token that +% is not a \ , \\ or a \par, it ceases and returns that token +% +% used to strip leading \, \\ and \par from the input +% so that such things in the beginning of an environment will not +% affect the formatting of the text +\long\def\@IEEEgobbleleadPARNLSP#1{\let\@IEEEswallowthistoken=0% +\let\@IEEEgobbleleadPARNLSPtoken#1% +\let\@IEEEgobbleleadPARtoken=\par% +\let\@IEEEgobbleleadNLtoken=\\% +\let\@IEEEgobbleleadSPtoken=\ % +\def\@IEEEgobbleleadSPMACRO{\ }% +\ifx\@IEEEgobbleleadPARNLSPtoken\@IEEEgobbleleadPARtoken% +\let\@IEEEswallowthistoken=1% +\fi% +\ifx\@IEEEgobbleleadPARNLSPtoken\@IEEEgobbleleadNLtoken% +\let\@IEEEswallowthistoken=1% +\fi% +\ifx\@IEEEgobbleleadPARNLSPtoken\@IEEEgobbleleadSPtoken% +\let\@IEEEswallowthistoken=1% +\fi% +% a control space will come in as a macro +% when it is the last one on a line +\ifx\@IEEEgobbleleadPARNLSPtoken\@IEEEgobbleleadSPMACRO% +\let\@IEEEswallowthistoken=1% +\fi% +% if we have to swallow this token, do so and taste the next one +% else spit it out and stop gobbling +\ifx\@IEEEswallowthistoken 1\let\@IEEEnextgobbleleadPARNLSP=\@IEEEgobbleleadPARNLSP\else% +\let\@IEEEnextgobbleleadPARNLSP=#1\fi% +\@IEEEnextgobbleleadPARNLSP}% + + + + +% TITLING OF SECTIONS +\def\@IEEEsectpunct{:\ \,} % Punctuation after run-in section heading (headings which are + % part of the paragraphs), need little bit more than a single space + % spacing from section number to title +% compsoc conferences use regular period/space punctuation +\ifCLASSOPTIONcompsoc +\ifCLASSOPTIONconference +\def\@IEEEsectpunct{.\ } +\fi\fi + + +\def\@seccntformat#1{\csname the#1dis\endcsname\hskip 0.5em\relax} + +\ifCLASSOPTIONcompsoc +% compsoc journals need extra spacing +\ifCLASSOPTIONconference\else +\def\@seccntformat#1{\csname the#1dis\endcsname\hskip 1em\relax} +\fi\fi + +%v1.7 put {} after #6 to allow for some types of user font control +%and use \@@par rather than \par +\def\@sect#1#2#3#4#5#6[#7]#8{% + \ifnum #2>\c@secnumdepth + \let\@svsec\@empty + \else + \refstepcounter{#1}% + % load section label and spacer into \@svsec + \protected@edef\@svsec{\@seccntformat{#1}\relax}% + \fi% + \@tempskipa #5\relax + \ifdim \@tempskipa>\z@% tempskipa determines whether is treated as a high + \begingroup #6{\relax% or low level heading + \noindent % subsections are NOT indented + % print top level headings. \@svsec is label, #8 is heading title + % IEEE does not block indent the section title text, it flows like normal + {\hskip #3\relax\@svsec}{\interlinepenalty \@M #8\@@par}}% + \endgroup + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth\relax\else + \protect\numberline{\csname the#1\endcsname}\fi#7}% + \else % printout low level headings + % svsechd seems to swallow the trailing space, protect it with \mbox{} + % got rid of sectionmark stuff + \def\@svsechd{#6{\hskip #3\relax\@svsec #8\@IEEEsectpunct\mbox{}}% + \addcontentsline{toc}{#1}{\ifnum #2>\c@secnumdepth\relax\else + \protect\numberline{\csname the#1\endcsname}\fi#7}}% + \fi%skip down + \@xsect{#5}} + + +% section* handler +%v1.7 put {} after #4 to allow for some types of user font control +%and use \@@par rather than \par +\def\@ssect#1#2#3#4#5{\@tempskipa #3\relax + \ifdim \@tempskipa>\z@ + %\begingroup #4\@hangfrom{\hskip #1}{\interlinepenalty \@M #5\par}\endgroup + % IEEE does not block indent the section title text, it flows like normal + \begingroup \noindent #4{\relax{\hskip #1}{\interlinepenalty \@M #5\@@par}}\endgroup + % svsechd swallows the trailing space, protect it with \mbox{} + \else \def\@svsechd{#4{\hskip #1\relax #5\@IEEEsectpunct\mbox{}}}\fi + \@xsect{#3}} + + +%% SECTION heading spacing and font +%% +% arguments are: #1 - sectiontype name +% (for \@sect) #2 - section level +% #3 - section heading indent +% #4 - top separation (absolute value used, neg indicates not to indent main text) +% If negative, make stretch parts negative too! +% #5 - (absolute value used) positive: bottom separation after heading, +% negative: amount to indent main text after heading +% Both #4 and #5 negative means to indent main text and use negative top separation +% #6 - font control +% You've got to have \normalfont\normalsize in the font specs below to prevent +% trouble when you do something like: +% \section{Note}{\ttfamily TT-TEXT} is known to ... +% IEEE sometimes REALLY stretches the area before a section +% heading by up to about 0.5in. However, it may not be a good +% idea to let LaTeX have quite this much rubber. +\ifCLASSOPTIONconference% +% IEEE wants section heading spacing to decrease for conference mode +\def\section{\@startsection{section}{1}{\z@}{1.5ex plus 1.5ex minus 0.5ex}% +{0.7ex plus 1ex minus 0ex}{\normalfont\normalsize\centering\scshape}}% +\def\subsection{\@startsection{subsection}{2}{\z@}{1.5ex plus 1.5ex minus 0.5ex}% +{0.7ex plus .5ex minus 0ex}{\normalfont\normalsize\itshape}}% +\else % for journals +\def\section{\@startsection{section}{1}{\z@}{3.0ex plus 1.5ex minus 1.5ex}% V1.6 3.0ex from 3.5ex +{0.7ex plus 1ex minus 0ex}{\normalfont\normalsize\centering\scshape}}% +\def\subsection{\@startsection{subsection}{2}{\z@}{3.5ex plus 1.5ex minus 1.5ex}% +{0.7ex plus .5ex minus 0ex}{\normalfont\normalsize\itshape}}% +\fi + +% for both journals and conferences +% decided to put in a little rubber above the section, might help somebody +\def\subsubsection{\@startsection{subsubsection}{3}{\parindent}{0ex plus 0.1ex minus 0.1ex}% +{0ex}{\normalfont\normalsize\itshape}}% +\def\paragraph{\@startsection{paragraph}{4}{2\parindent}{0ex plus 0.1ex minus 0.1ex}% +{0ex}{\normalfont\normalsize\itshape}}% + + +% compsoc +\ifCLASSOPTIONcompsoc +\ifCLASSOPTIONconference +% compsoc conference +\def\section{\@startsection{section}{1}{\z@}{1\baselineskip plus 0.25\baselineskip minus 0.25\baselineskip}% +{1\baselineskip plus 0.25\baselineskip minus 0.25\baselineskip}{\normalfont\large\bfseries}}% +\def\subsection{\@startsection{subsection}{2}{\z@}{1\baselineskip plus 0.25\baselineskip minus 0.25\baselineskip}% +{1\baselineskip plus 0.25\baselineskip minus 0.25\baselineskip}{\normalfont\sublargesize\bfseries}}% +\def\subsubsection{\@startsection{subsubsection}{3}{\z@}{1\baselineskip plus 0.25\baselineskip minus 0.25\baselineskip}% +{0ex}{\normalfont\normalsize\bfseries}}% +\def\paragraph{\@startsection{paragraph}{4}{2\parindent}{0ex plus 0.1ex minus 0.1ex}% +{0ex}{\normalfont\normalsize}}% +\else% compsoc journals +% use negative top separation as compsoc journals do not indent paragraphs after section titles +\def\section{\@startsection{section}{1}{\z@}{-3ex plus -2ex minus -1.5ex}% +{0.7ex plus 1ex minus 0ex}{\normalfont\large\sffamily\bfseries\scshape}}% +% Note that subsection and smaller may not be correct for the Computer Society, +% I have to look up an example. +\def\subsection{\@startsection{subsection}{2}{\z@}{-3.5ex plus -1.5ex minus -1.5ex}% +{0.7ex plus .5ex minus 0ex}{\normalfont\normalsize\sffamily\bfseries}}% +\def\subsubsection{\@startsection{subsubsection}{3}{\z@}{-2.5ex plus -1ex minus -1ex}% +{0.5ex plus 0.5ex minus 0ex}{\normalfont\normalsize\sffamily\itshape}}% +\def\paragraph{\@startsection{paragraph}{4}{2\parindent}{-0ex plus -0.1ex minus -0.1ex}% +{0ex}{\normalfont\normalsize}}% +\fi\fi + + + + +%% ENVIRONMENTS +% "box" symbols at end of proofs +\def\IEEEQEDclosed{\mbox{\rule[0pt]{1.3ex}{1.3ex}}} % for a filled box +% V1.6 some journals use an open box instead that will just fit around a closed one +\def\IEEEQEDopen{{\setlength{\fboxsep}{0pt}\setlength{\fboxrule}{0.2pt}\fbox{\rule[0pt]{0pt}{1.3ex}\rule[0pt]{1.3ex}{0pt}}}} +\ifCLASSOPTIONcompsoc +\def\IEEEQED{\IEEEQEDopen} % default to open for compsoc +\else +\def\IEEEQED{\IEEEQEDclosed} % otherwise default to closed +\fi + +% v1.7 name change to avoid namespace collision with amsthm. Also add support +% for an optional argument. +\def\IEEEproof{\@ifnextchar[{\@IEEEproof}{\@IEEEproof[\IEEEproofname]}} +\def\@IEEEproof[#1]{\par\noindent\hspace{2em}{\itshape #1: }} +\def\endIEEEproof{\hspace*{\fill}~\IEEEQED\par} + + +%\itemindent is set to \z@ by list, so define new temporary variable +\newdimen\@IEEEtmpitemindent +\def\@begintheorem#1#2{\@IEEEtmpitemindent\itemindent\topsep 0pt\rmfamily\trivlist% + \item[\hskip \labelsep{\indent\itshape #1\ #2:}]\itemindent\@IEEEtmpitemindent} +\def\@opargbegintheorem#1#2#3{\@IEEEtmpitemindent\itemindent\topsep 0pt\rmfamily \trivlist% +% V1.6 IEEE is back to using () around theorem names which are also in italics +% Thanks to Christian Peel for reporting this. + \item[\hskip\labelsep{\indent\itshape #1\ #2\ (#3):}]\itemindent\@IEEEtmpitemindent} +% V1.7 remove bogus \unskip that caused equations in theorems to collide with +% lines below. +\def\@endtheorem{\endtrivlist} + +% V1.6 +% display command for the section the theorem is in - so that \thesection +% is not used as this will be in Roman numerals when we want arabic. +% LaTeX2e uses \def\@thmcounter#1{\noexpand\arabic{#1}} for the theorem number +% (second part) display and \def\@thmcountersep{.} as a separator. +% V1.7 intercept calls to the section counter and reroute to \@IEEEthmcounterinsection +% to allow \appendix(ices} to override as needed. +% +% special handler for sections, allows appendix(ices) to override +\gdef\@IEEEthmcounterinsection#1{\arabic{#1}} +% string macro +\edef\@IEEEstringsection{section} + +% redefine the #1#2[#3] form of newtheorem to use a hook to \@IEEEthmcounterinsection +% if section in_counter is used +\def\@xnthm#1#2[#3]{% + \expandafter\@ifdefinable\csname #1\endcsname + {\@definecounter{#1}\@newctr{#1}[#3]% + \edef\@IEEEstringtmp{#3} + \ifx\@IEEEstringtmp\@IEEEstringsection + \expandafter\xdef\csname the#1\endcsname{% + \noexpand\@IEEEthmcounterinsection{#3}\@thmcountersep + \@thmcounter{#1}}% + \else + \expandafter\xdef\csname the#1\endcsname{% + \expandafter\noexpand\csname the#3\endcsname \@thmcountersep + \@thmcounter{#1}}% + \fi + \global\@namedef{#1}{\@thm{#1}{#2}}% + \global\@namedef{end#1}{\@endtheorem}}} + + + +%% SET UP THE DEFAULT PAGESTYLE +\ps@headings +\pagenumbering{arabic} + +% normally the page counter starts at 1 +\setcounter{page}{1} +% however, for peerreview the cover sheet is page 0 or page -1 +% (for duplex printing) +\ifCLASSOPTIONpeerreview + \if@twoside + \setcounter{page}{-1} + \else + \setcounter{page}{0} + \fi +\fi + +% standard book class behavior - let bottom line float up and down as +% needed when single sided +\ifCLASSOPTIONtwoside\else\raggedbottom\fi +% if two column - turn on twocolumn, allow word spacings to stretch more and +% enforce a rigid position for the last lines +\ifCLASSOPTIONtwocolumn +% the peer review option delays invoking twocolumn + \ifCLASSOPTIONpeerreview\else + \twocolumn + \fi +\sloppy +\flushbottom +\fi + + + + +% \APPENDIX and \APPENDICES definitions + +% This is the \@ifmtarg command from the LaTeX ifmtarg package +% by Peter Wilson (CUA) and Donald Arseneau +% \@ifmtarg is used to determine if an argument to a command +% is present or not. +% For instance: +% \@ifmtarg{#1}{\typeout{empty}}{\typeout{has something}} +% \@ifmtarg is used with our redefined \section command if +% \appendices is invoked. +% The command \section will behave slightly differently depending +% on whether the user specifies a title: +% \section{My appendix title} +% or not: +% \section{} +% This way, we can eliminate the blank lines where the title +% would be, and the unneeded : after Appendix in the table of +% contents +\begingroup +\catcode`\Q=3 +\long\gdef\@ifmtarg#1{\@xifmtarg#1QQ\@secondoftwo\@firstoftwo\@nil} +\long\gdef\@xifmtarg#1#2Q#3#4#5\@nil{#4} +\endgroup +% end of \@ifmtarg defs + + +% V1.7 +% command that allows the one time saving of the original definition +% of section to \@IEEEappendixsavesection for \appendix or \appendices +% we don't save \section here as it may be redefined later by other +% packages (hyperref.sty, etc.) +\def\@IEEEsaveoriginalsectiononce{\let\@IEEEappendixsavesection\section +\let\@IEEEsaveoriginalsectiononce\relax} + +% neat trick to grab and process the argument from \section{argument} +% we process differently if the user invoked \section{} with no +% argument (title) +% note we reroute the call to the old \section* +\def\@IEEEprocessthesectionargument#1{% +\@ifmtarg{#1}{% +\@IEEEappendixsavesection*{\appendixname~\thesectiondis}% +\addcontentsline{toc}{section}{\appendixname~\thesection}}{% +\@IEEEappendixsavesection*{\appendixname~\thesectiondis \\* #1}% +\addcontentsline{toc}{section}{\appendixname~\thesection: #1}}} + +% we use this if the user calls \section{} after +% \appendix-- which has no meaning. So, we ignore the +% command and its argument. Then, warn the user. +\def\@IEEEdestroythesectionargument#1{\typeout{** WARNING: Ignoring useless +\protect\section\space in Appendix (line \the\inputlineno).}} + + +% remember \thesection forms will be displayed in \ref calls +% and in the Table of Contents. +% The \sectiondis form is used in the actual heading itself + +% appendix command for one single appendix +% normally has no heading. However, if you want a +% heading, you can do so via the optional argument: +% \appendix[Optional Heading] +\def\appendix{\relax} +\renewcommand{\appendix}[1][]{\@IEEEsaveoriginalsectiononce\par + % v1.6 keep hyperref's identifiers unique + \gdef\theHsection{Appendix.A}% + % v1.6 adjust hyperref's string name for the section + \xdef\Hy@chapapp{appendix}% + \setcounter{section}{0}% + \setcounter{subsection}{0}% + \setcounter{subsubsection}{0}% + \setcounter{paragraph}{0}% + \gdef\thesection{A}% + \gdef\thesectiondis{}% + \gdef\thesubsection{\Alph{subsection}}% + \gdef\@IEEEthmcounterinsection##1{A} + \refstepcounter{section}% update the \ref counter + \@ifmtarg{#1}{\@IEEEappendixsavesection*{\appendixname}% + \addcontentsline{toc}{section}{\appendixname}}{% + \@IEEEappendixsavesection*{\appendixname~\\* #1}% + \addcontentsline{toc}{section}{\appendixname: #1}}% + % redefine \section command for appendix + % leave \section* as is + \def\section{\@ifstar{\@IEEEappendixsavesection*}{% + \@IEEEdestroythesectionargument}}% throw out the argument + % of the normal form +} + + + +% appendices command for multiple appendices +% user then calls \section with an argument (possibly empty) to +% declare the individual appendices +\def\appendices{\@IEEEsaveoriginalsectiononce\par + % v1.6 keep hyperref's identifiers unique + \gdef\theHsection{Appendix.\Alph{section}}% + % v1.6 adjust hyperref's string name for the section + \xdef\Hy@chapapp{appendix}% + \setcounter{section}{-1}% we want \refstepcounter to use section 0 + \setcounter{subsection}{0}% + \setcounter{subsubsection}{0}% + \setcounter{paragraph}{0}% + \ifCLASSOPTIONromanappendices% + \gdef\thesection{\Roman{section}}% + \gdef\thesectiondis{\Roman{section}}% + \@IEEEcompsocconfonly{\gdef\thesectiondis{\Roman{section}.}}% + \gdef\@IEEEthmcounterinsection##1{A\arabic{##1}} + \else% + \gdef\thesection{\Alph{section}}% + \gdef\thesectiondis{\Alph{section}}% + \@IEEEcompsocconfonly{\gdef\thesectiondis{\Alph{section}.}}% + \gdef\@IEEEthmcounterinsection##1{\Alph{##1}} + \fi% + \refstepcounter{section}% update the \ref counter + \setcounter{section}{0}% NEXT \section will be the FIRST appendix + % redefine \section command for appendices + % leave \section* as is + \def\section{\@ifstar{\@IEEEappendixsavesection*}{% process the *-form + \refstepcounter{section}% or is a new section so, + \@IEEEprocessthesectionargument}}% process the argument + % of the normal form +} + + + +% \IEEEPARstart +% Definition for the big two line drop cap letter at the beginning of the +% first paragraph of journal papers. The first argument is the first letter +% of the first word, the second argument is the remaining letters of the +% first word which will be rendered in upper case. +% In V1.6 this has been completely rewritten to: +% +% 1. no longer have problems when the user begins an environment +% within the paragraph that uses \IEEEPARstart. +% 2. auto-detect and use the current font family +% 3. revise handling of the space at the end of the first word so that +% interword glue will now work as normal. +% 4. produce correctly aligned edges for the (two) indented lines. +% +% We generalize things via control macros - playing with these is fun too. +% +% V1.7 added more control macros to make it easy for IEEEtrantools.sty users +% to change the font style. +% +% the number of lines that are indented to clear it +% may need to increase if using decenders +\def\@IEEEPARstartDROPLINES{2} +% minimum number of lines left on a page to allow a \@IEEEPARstart +% Does not take into consideration rubber shrink, so it tends to +% be overly cautious +\def\@IEEEPARstartMINPAGELINES{2} +% V1.7 the height of the drop cap is adjusted to match the height of this text +% in the current font (when \IEEEPARstart is called). +\def\@IEEEPARstartHEIGHTTEXT{T} +% the depth the letter is lowered below the baseline +% the height (and size) of the letter is determined by the sum +% of this value and the height of the \@IEEEPARstartHEIGHTTEXT in the current +% font. It is a good idea to set this value in terms of the baselineskip +% so that it can respond to changes therein. +\def\@IEEEPARstartDROPDEPTH{1.1\baselineskip} +% V1.7 the font the drop cap will be rendered in, +% can take zero or one argument. +\def\@IEEEPARstartFONTSTYLE{\bfseries} +% V1.7 any additional, non-font related commands needed to modify +% the drop cap letter, can take zero or one argument. +\def\@IEEEPARstartCAPSTYLE{\MakeUppercase} +% V1.7 the font that will be used to render the rest of the word, +% can take zero or one argument. +\def\@IEEEPARstartWORDFONTSTYLE{\relax} +% V1.7 any additional, non-font related commands needed to modify +% the rest of the word, can take zero or one argument. +\def\@IEEEPARstartWORDCAPSTYLE{\MakeUppercase} +% This is the horizontal separation distance from the drop letter to the main text. +% Lengths that depend on the font (e.g., ex, em, etc.) will be referenced +% to the font that is active when \IEEEPARstart is called. +\def\@IEEEPARstartSEP{0.15em} +% V1.7 horizontal offset applied to the left of the drop cap. +\def\@IEEEPARstartHOFFSET{0em} +% V1.7 Italic correction command applied at the end of the drop cap. +\def\@IEEEPARstartITLCORRECT{\/} + +% V1.7 compoc uses nonbold drop cap and small caps word style +\ifCLASSOPTIONcompsoc +\def\@IEEEPARstartFONTSTYLE{\mdseries} +\def\@IEEEPARstartWORDFONTSTYLE{\scshape} +\def\@IEEEPARstartWORDCAPSTYLE{\relax} +\fi + +% definition of \IEEEPARstart +% THIS IS A CONTROLLED SPACING AREA, DO NOT ALLOW SPACES WITHIN THESE LINES +% +% The token \@IEEEPARstartfont will be globally defined after the first use +% of \IEEEPARstart and will be a font command which creates the big letter +% The first argument is the first letter of the first word and the second +% argument is the rest of the first word(s). +\def\IEEEPARstart#1#2{\par{% +% if this page does not have enough space, break it and lets start +% on a new one +\@IEEEtranneedspace{\@IEEEPARstartMINPAGELINES\baselineskip}{\relax}% +% V1.7 move this up here in case user uses \textbf for \@IEEEPARstartFONTSTYLE +% which uses command \leavevmode which causes an unwanted \indent to be issued +\noindent +% calculate the desired height of the big letter +% it extends from the top of \@IEEEPARstartHEIGHTTEXT in the current font +% down to \@IEEEPARstartDROPDEPTH below the current baseline +\settoheight{\@IEEEtrantmpdimenA}{\@IEEEPARstartHEIGHTTEXT}% +\addtolength{\@IEEEtrantmpdimenA}{\@IEEEPARstartDROPDEPTH}% +% extract the name of the current font in bold +% and place it in \@IEEEPARstartFONTNAME +\def\@IEEEPARstartGETFIRSTWORD##1 ##2\relax{##1}% +{\@IEEEPARstartFONTSTYLE{\selectfont\edef\@IEEEPARstartFONTNAMESPACE{\fontname\font\space}% +\xdef\@IEEEPARstartFONTNAME{\expandafter\@IEEEPARstartGETFIRSTWORD\@IEEEPARstartFONTNAMESPACE\relax}}}% +% define a font based on this name with a point size equal to the desired +% height of the drop letter +\font\@IEEEPARstartsubfont\@IEEEPARstartFONTNAME\space at \@IEEEtrantmpdimenA\relax% +% save this value as a counter (integer) value (sp points) +\@IEEEtrantmpcountA=\@IEEEtrantmpdimenA% +% now get the height of the actual letter produced by this font size +\settoheight{\@IEEEtrantmpdimenB}{\@IEEEPARstartsubfont\@IEEEPARstartCAPSTYLE{#1}}% +% If something bogus happens like the first argument is empty or the +% current font is strange, do not allow a zero height. +\ifdim\@IEEEtrantmpdimenB=0pt\relax% +\typeout{** WARNING: IEEEPARstart drop letter has zero height! (line \the\inputlineno)}% +\typeout{ Forcing the drop letter font size to 10pt.}% +\@IEEEtrantmpdimenB=10pt% +\fi% +% and store it as a counter +\@IEEEtrantmpcountB=\@IEEEtrantmpdimenB% +% Since a font size doesn't exactly correspond to the height of the capital +% letters in that font, the actual height of the letter, \@IEEEtrantmpcountB, +% will be less than that desired, \@IEEEtrantmpcountA +% we need to raise the font size, \@IEEEtrantmpdimenA +% by \@IEEEtrantmpcountA / \@IEEEtrantmpcountB +% But, TeX doesn't have floating point division, so we have to use integer +% division. Hence the use of the counters. +% We need to reduce the denominator so that the loss of the remainder will +% have minimal affect on the accuracy of the result +\divide\@IEEEtrantmpcountB by 200% +\divide\@IEEEtrantmpcountA by \@IEEEtrantmpcountB% +% Then reequalize things when we use TeX's ability to multiply by +% floating point values +\@IEEEtrantmpdimenB=0.005\@IEEEtrantmpdimenA% +\multiply\@IEEEtrantmpdimenB by \@IEEEtrantmpcountA% +% \@IEEEPARstartfont is globaly set to the calculated font of the big letter +% We need to carry this out of the local calculation area to to create the +% big letter. +\global\font\@IEEEPARstartfont\@IEEEPARstartFONTNAME\space at \@IEEEtrantmpdimenB% +% Now set \@IEEEtrantmpdimenA to the width of the big letter +% We need to carry this out of the local calculation area to set the +% hanging indent +\settowidth{\global\@IEEEtrantmpdimenA}{\@IEEEPARstartfont +\@IEEEPARstartCAPSTYLE{#1\@IEEEPARstartITLCORRECT}}}% +% end of the isolated calculation environment +% add in the extra clearance we want +\advance\@IEEEtrantmpdimenA by \@IEEEPARstartSEP\relax% +% add in the optional offset +\advance\@IEEEtrantmpdimenA by \@IEEEPARstartHOFFSET\relax% +% V1.7 don't allow negative offsets to produce negative hanging indents +\@IEEEtrantmpdimenB\@IEEEtrantmpdimenA +\ifnum\@IEEEtrantmpdimenB < 0 \@IEEEtrantmpdimenB 0pt\fi +% \@IEEEtrantmpdimenA has the width of the big letter plus the +% separation space and \@IEEEPARstartfont is the font we need to use +% Now, we make the letter and issue the hanging indent command +% The letter is placed in a box of zero width and height so that other +% text won't be displaced by it. +\hangindent\@IEEEtrantmpdimenB\hangafter=-\@IEEEPARstartDROPLINES% +\makebox[0pt][l]{\hspace{-\@IEEEtrantmpdimenA}% +\raisebox{-\@IEEEPARstartDROPDEPTH}[0pt][0pt]{\hspace{\@IEEEPARstartHOFFSET}% +\@IEEEPARstartfont\@IEEEPARstartCAPSTYLE{#1\@IEEEPARstartITLCORRECT}% +\hspace{\@IEEEPARstartSEP}}}% +{\@IEEEPARstartWORDFONTSTYLE{\@IEEEPARstartWORDCAPSTYLE{\selectfont#2}}}} + + + + + + +% determines if the space remaining on a given page is equal to or greater +% than the specified space of argument one +% if not, execute argument two (only if the remaining space is greater than zero) +% and issue a \newpage +% +% example: \@IEEEtranneedspace{2in}{\vfill} +% +% Does not take into consideration rubber shrinkage, so it tends to +% be overly cautious +% Based on an example posted by Donald Arseneau +% Note this macro uses \@IEEEtrantmpdimenB internally for calculations, +% so DO NOT PASS \@IEEEtrantmpdimenB to this routine +% if you need a dimen register, import with \@IEEEtrantmpdimenA instead +\def\@IEEEtranneedspace#1#2{\penalty-100\begingroup%shield temp variable +\@IEEEtrantmpdimenB\pagegoal\advance\@IEEEtrantmpdimenB-\pagetotal% space left +\ifdim #1>\@IEEEtrantmpdimenB\relax% not enough space left +\ifdim\@IEEEtrantmpdimenB>\z@\relax #2\fi% +\newpage% +\fi\endgroup} + + + +% IEEEbiography ENVIRONMENT +% Allows user to enter biography leaving place for picture (adapts to font size) +% As of V1.5, a new optional argument allows you to have a real graphic! +% V1.5 and later also fixes the "colliding biographies" which could happen when a +% biography's text was shorter than the space for the photo. +% MDS 7/2001 +% V1.6 prevent multiple biographies from making multiple TOC entries +\newif\if@IEEEbiographyTOCentrynotmade +\global\@IEEEbiographyTOCentrynotmadetrue + +% biography counter so hyperref can jump directly to the biographies +% and not just the previous section +\newcounter{IEEEbiography} +\setcounter{IEEEbiography}{0} + +% photo area size +\def\@IEEEBIOphotowidth{1.0in} % width of the biography photo area +\def\@IEEEBIOphotodepth{1.25in} % depth (height) of the biography photo area +% area cleared for photo +\def\@IEEEBIOhangwidth{1.14in} % width cleared for the biography photo area +\def\@IEEEBIOhangdepth{1.25in} % depth cleared for the biography photo area + % actual depth will be a multiple of + % \baselineskip, rounded up +\def\@IEEEBIOskipN{4\baselineskip}% nominal value of the vskip above the biography + +\newenvironment{IEEEbiography}[2][]{\normalfont\@IEEEcompsoconly{\sffamily}\footnotesize% +\unitlength 1in\parskip=0pt\par\parindent 1em\interlinepenalty500% +% we need enough space to support the hanging indent +% the nominal value of the spacer +% and one extra line for good measure +\@IEEEtrantmpdimenA=\@IEEEBIOhangdepth% +\advance\@IEEEtrantmpdimenA by \@IEEEBIOskipN% +\advance\@IEEEtrantmpdimenA by 1\baselineskip% +% if this page does not have enough space, break it and lets start +% with a new one +\@IEEEtranneedspace{\@IEEEtrantmpdimenA}{\relax}% +% nominal spacer can strech, not shrink use 1fil so user can out stretch with \vfill +\vskip \@IEEEBIOskipN plus 1fil minus 0\baselineskip% +% the default box for where the photo goes +\def\@IEEEtempbiographybox{{\setlength{\fboxsep}{0pt}\framebox{% +\begin{minipage}[b][\@IEEEBIOphotodepth][c]{\@IEEEBIOphotowidth}\centering PLACE\\ PHOTO\\ HERE \end{minipage}}}}% +% +% detect if the optional argument was supplied, this requires the +% \@ifmtarg command as defined in the appendix section above +% and if so, override the default box with what they want +\@ifmtarg{#1}{\relax}{\def\@IEEEtempbiographybox{\mbox{\begin{minipage}[b][\@IEEEBIOphotodepth][c]{\@IEEEBIOphotowidth}% +\centering% +#1% +\end{minipage}}}}% end if optional argument supplied +% Make an entry into the table of contents only if we have not done so before +\if@IEEEbiographyTOCentrynotmade% +% link labels to the biography counter so hyperref will jump +% to the biography, not the previous section +\setcounter{IEEEbiography}{-1}% +\refstepcounter{IEEEbiography}% +\addcontentsline{toc}{section}{Biographies}% +\global\@IEEEbiographyTOCentrynotmadefalse% +\fi% +% one more biography +\refstepcounter{IEEEbiography}% +% Make an entry for this name into the table of contents +\addcontentsline{toc}{subsection}{#2}% +% V1.6 properly handle if a new paragraph should occur while the +% hanging indent is still active. Do this by redefining \par so +% that it will not start a new paragraph. (But it will appear to the +% user as if it did.) Also, strip any leading pars, newlines, or spaces. +\let\@IEEEBIOORGparCMD=\par% save the original \par command +\edef\par{\hfil\break\indent}% the new \par will not be a "real" \par +\settoheight{\@IEEEtrantmpdimenA}{\@IEEEtempbiographybox}% get height of biography box +\@IEEEtrantmpdimenB=\@IEEEBIOhangdepth% +\@IEEEtrantmpcountA=\@IEEEtrantmpdimenB% countA has the hang depth +\divide\@IEEEtrantmpcountA by \baselineskip% calculates lines needed to produce the hang depth +\advance\@IEEEtrantmpcountA by 1% ensure we overestimate +% set the hanging indent +\hangindent\@IEEEBIOhangwidth% +\hangafter-\@IEEEtrantmpcountA% +% reference the top of the photo area to the top of a capital T +\settoheight{\@IEEEtrantmpdimenB}{\mbox{T}}% +% set the photo box, give it zero width and height so as not to disturb anything +\noindent\makebox[0pt][l]{\hspace{-\@IEEEBIOhangwidth}\raisebox{\@IEEEtrantmpdimenB}[0pt][0pt]{% +\raisebox{-\@IEEEBIOphotodepth}[0pt][0pt]{\@IEEEtempbiographybox}}}% +% now place the author name and begin the bio text +\noindent\textbf{#2\ }\@IEEEgobbleleadPARNLSP}{\relax\let\par=\@IEEEBIOORGparCMD\par% +% 7/2001 V1.5 detect when the biography text is shorter than the photo area +% and pad the unused area - preventing a collision from the next biography entry +% MDS +\ifnum \prevgraf <\@IEEEtrantmpcountA\relax% detect when the biography text is shorter than the photo + \advance\@IEEEtrantmpcountA by -\prevgraf% calculate how many lines we need to pad + \advance\@IEEEtrantmpcountA by -1\relax% we compensate for the fact that we indented an extra line + \@IEEEtrantmpdimenA=\baselineskip% calculate the length of the padding + \multiply\@IEEEtrantmpdimenA by \@IEEEtrantmpcountA% + \noindent\rule{0pt}{\@IEEEtrantmpdimenA}% insert an invisible support strut +\fi% +\par\normalfont} + + + +% V1.6 +% added biography without a photo environment +\newenvironment{IEEEbiographynophoto}[1]{% +% Make an entry into the table of contents only if we have not done so before +\if@IEEEbiographyTOCentrynotmade% +% link labels to the biography counter so hyperref will jump +% to the biography, not the previous section +\setcounter{IEEEbiography}{-1}% +\refstepcounter{IEEEbiography}% +\addcontentsline{toc}{section}{Biographies}% +\global\@IEEEbiographyTOCentrynotmadefalse% +\fi% +% one more biography +\refstepcounter{IEEEbiography}% +% Make an entry for this name into the table of contents +\addcontentsline{toc}{subsection}{#1}% +\normalfont\@IEEEcompsoconly{\sffamily}\footnotesize\interlinepenalty500% +\vskip 4\baselineskip plus 1fil minus 0\baselineskip% +\parskip=0pt\par% +\noindent\textbf{#1\ }\@IEEEgobbleleadPARNLSP}{\relax\par\normalfont} + + +% provide the user with some old font commands +% got this from article.cls +\DeclareOldFontCommand{\rm}{\normalfont\rmfamily}{\mathrm} +\DeclareOldFontCommand{\sf}{\normalfont\sffamily}{\mathsf} +\DeclareOldFontCommand{\tt}{\normalfont\ttfamily}{\mathtt} +\DeclareOldFontCommand{\bf}{\normalfont\bfseries}{\mathbf} +\DeclareOldFontCommand{\it}{\normalfont\itshape}{\mathit} +\DeclareOldFontCommand{\sl}{\normalfont\slshape}{\@nomath\sl} +\DeclareOldFontCommand{\sc}{\normalfont\scshape}{\@nomath\sc} +\DeclareRobustCommand*\cal{\@fontswitch\relax\mathcal} +\DeclareRobustCommand*\mit{\@fontswitch\relax\mathnormal} + + +% SPECIAL PAPER NOTICE COMMANDS +% +% holds the special notice text +\def\@IEEEspecialpapernotice{\relax} + +% for special papers, like invited papers, the user can do: +% \IEEEspecialpapernotice{(Invited Paper)} before \maketitle +\def\IEEEspecialpapernotice#1{\ifCLASSOPTIONconference% +\def\@IEEEspecialpapernotice{{\sublargesize\textit{#1}\vspace*{1em}}}% +\else% +\def\@IEEEspecialpapernotice{{\\*[1.5ex]\sublargesize\textit{#1}}\vspace*{-2ex}}% +\fi} + + + + +% PUBLISHER ID COMMANDS +% to insert a publisher's ID footer +% V1.6 \IEEEpubid has been changed so that the change in page size and style +% occurs in \maketitle. \IEEEpubid must now be issued prior to \maketitle +% use \IEEEpubidadjcol as before - in the second column of the title page +% These changes allow \maketitle to take the reduced page height into +% consideration when dynamically setting the space between the author +% names and the maintext. +% +% the amount the main text is pulled up to make room for the +% publisher's ID footer +% IEEE uses about 1.3\baselineskip for journals, +% dynamic title spacing will clean up the fraction +\def\@IEEEpubidpullup{1.3\baselineskip} +\ifCLASSOPTIONtechnote +% for technotes it must be an integer of baselineskip as there can be no +% dynamic title spacing for two column mode technotes (the title is in the +% in first column) and we should maintain an integer number of lines in the +% second column +% There are some examples (such as older issues of "Transactions on +% Information Theory") in which IEEE really pulls the text off the ID for +% technotes - about 0.55in (or 4\baselineskip). We'll use 2\baselineskip +% and call it even. +\def\@IEEEpubidpullup{2\baselineskip} +\fi + +% V1.7 compsoc does not use a pullup +\ifCLASSOPTIONcompsoc +\def\@IEEEpubidpullup{0pt} +\fi + +% holds the ID text +\def\@IEEEpubid{\relax} + +% flag so \maketitle can tell if \IEEEpubid was called +\newif\if@IEEEusingpubid +\global\@IEEEusingpubidfalse +% issue this command in the page to have the ID at the bottom +% V1.6 use before \maketitle +\def\IEEEpubid#1{\def\@IEEEpubid{#1}\global\@IEEEusingpubidtrue} + + +% command which will pull up (shorten) the column it is executed in +% to make room for the publisher ID. Place in the second column of +% the title page when using \IEEEpubid +% Is smart enough not to do anything when in single column text or +% if the user hasn't called \IEEEpubid +% currently needed in for the second column of a page with the +% publisher ID. If not needed in future releases, please provide this +% command and define it as \relax for backward compatibility +% v1.6b do not allow command to operate if the peer review option has been +% selected because \IEEEpubidadjcol will not be on the cover page. +% V1.7 do nothing if compsoc +\def\IEEEpubidadjcol{\ifCLASSOPTIONcompsoc\else\ifCLASSOPTIONpeerreview\else +\if@twocolumn\if@IEEEusingpubid\enlargethispage{-\@IEEEpubidpullup}\fi\fi\fi\fi} + +% Special thanks to Peter Wilson, Daniel Luecking, and the other +% gurus at comp.text.tex, for helping me to understand how best to +% implement the IEEEpubid command in LaTeX. + + + +%% Lockout some commands under various conditions + +% general purpose bit bucket +\newsavebox{\@IEEEtranrubishbin} + +% flags to prevent multiple warning messages +\newif\if@IEEEWARNthanks +\newif\if@IEEEWARNIEEEPARstart +\newif\if@IEEEWARNIEEEbiography +\newif\if@IEEEWARNIEEEbiographynophoto +\newif\if@IEEEWARNIEEEpubid +\newif\if@IEEEWARNIEEEpubidadjcol +\newif\if@IEEEWARNIEEEmembership +\newif\if@IEEEWARNIEEEaftertitletext +\@IEEEWARNthankstrue +\@IEEEWARNIEEEPARstarttrue +\@IEEEWARNIEEEbiographytrue +\@IEEEWARNIEEEbiographynophototrue +\@IEEEWARNIEEEpubidtrue +\@IEEEWARNIEEEpubidadjcoltrue +\@IEEEWARNIEEEmembershiptrue +\@IEEEWARNIEEEaftertitletexttrue + + +%% Lockout some commands when in various modes, but allow them to be restored if needed +%% +% save commands which might be locked out +% so that the user can later restore them if needed +\let\@IEEESAVECMDthanks\thanks +\let\@IEEESAVECMDIEEEPARstart\IEEEPARstart +\let\@IEEESAVECMDIEEEbiography\IEEEbiography +\let\@IEEESAVECMDendIEEEbiography\endIEEEbiography +\let\@IEEESAVECMDIEEEbiographynophoto\IEEEbiographynophoto +\let\@IEEESAVECMDendIEEEbiographynophoto\endIEEEbiographynophoto +\let\@IEEESAVECMDIEEEpubid\IEEEpubid +\let\@IEEESAVECMDIEEEpubidadjcol\IEEEpubidadjcol +\let\@IEEESAVECMDIEEEmembership\IEEEmembership +\let\@IEEESAVECMDIEEEaftertitletext\IEEEaftertitletext + + +% disable \IEEEPARstart when in draft mode +% This may have originally been done because the pre-V1.6 drop letter +% algorithm had problems with a non-unity baselinestretch +% At any rate, it seems too formal to have a drop letter in a draft +% paper. +\ifCLASSOPTIONdraftcls +\def\IEEEPARstart#1#2{#1#2\if@IEEEWARNIEEEPARstart\typeout{** ATTENTION: \noexpand\IEEEPARstart + is disabled in draft mode (line \the\inputlineno).}\fi\global\@IEEEWARNIEEEPARstartfalse} +\fi +% and for technotes +\ifCLASSOPTIONtechnote +\def\IEEEPARstart#1#2{#1#2\if@IEEEWARNIEEEPARstart\typeout{** WARNING: \noexpand\IEEEPARstart + is locked out for technotes (line \the\inputlineno).}\fi\global\@IEEEWARNIEEEPARstartfalse} +\fi + + +% lockout unneeded commands when in conference mode +\ifCLASSOPTIONconference +% when locked out, \thanks, \IEEEbiography, \IEEEbiographynophoto, \IEEEpubid, +% \IEEEmembership and \IEEEaftertitletext will all swallow their given text. +% \IEEEPARstart will output a normal character instead +% warn the user about these commands only once to prevent the console screen +% from filling up with redundant messages +\def\thanks#1{\if@IEEEWARNthanks\typeout{** WARNING: \noexpand\thanks + is locked out when in conference mode (line \the\inputlineno).}\fi\global\@IEEEWARNthanksfalse} +\def\IEEEPARstart#1#2{#1#2\if@IEEEWARNIEEEPARstart\typeout{** WARNING: \noexpand\IEEEPARstart + is locked out when in conference mode (line \the\inputlineno).}\fi\global\@IEEEWARNIEEEPARstartfalse} + + +% LaTeX treats environments and commands with optional arguments differently. +% the actual ("internal") command is stored as \\commandname +% (accessed via \csname\string\commandname\endcsname ) +% the "external" command \commandname is a macro with code to determine +% whether or not the optional argument is presented and to provide the +% default if it is absent. So, in order to save and restore such a command +% we would have to save and restore \\commandname as well. But, if LaTeX +% ever changes the way it names the internal names, the trick would break. +% Instead let us just define a new environment so that the internal +% name can be left undisturbed. +\newenvironment{@IEEEbogusbiography}[2][]{\if@IEEEWARNIEEEbiography\typeout{** WARNING: \noexpand\IEEEbiography + is locked out when in conference mode (line \the\inputlineno).}\fi\global\@IEEEWARNIEEEbiographyfalse% +\setbox\@IEEEtranrubishbin\vbox\bgroup}{\egroup\relax} +% and make biography point to our bogus biography +\let\IEEEbiography=\@IEEEbogusbiography +\let\endIEEEbiography=\end@IEEEbogusbiography + +\renewenvironment{IEEEbiographynophoto}[1]{\if@IEEEWARNIEEEbiographynophoto\typeout{** WARNING: \noexpand\IEEEbiographynophoto + is locked out when in conference mode (line \the\inputlineno).}\fi\global\@IEEEWARNIEEEbiographynophotofalse% +\setbox\@IEEEtranrubishbin\vbox\bgroup}{\egroup\relax} + +\def\IEEEpubid#1{\if@IEEEWARNIEEEpubid\typeout{** WARNING: \noexpand\IEEEpubid + is locked out when in conference mode (line \the\inputlineno).}\fi\global\@IEEEWARNIEEEpubidfalse} +\def\IEEEpubidadjcol{\if@IEEEWARNIEEEpubidadjcol\typeout{** WARNING: \noexpand\IEEEpubidadjcol + is locked out when in conference mode (line \the\inputlineno).}\fi\global\@IEEEWARNIEEEpubidadjcolfalse} +\def\IEEEmembership#1{\if@IEEEWARNIEEEmembership\typeout{** WARNING: \noexpand\IEEEmembership + is locked out when in conference mode (line \the\inputlineno).}\fi\global\@IEEEWARNIEEEmembershipfalse} +\def\IEEEaftertitletext#1{\if@IEEEWARNIEEEaftertitletext\typeout{** WARNING: \noexpand\IEEEaftertitletext + is locked out when in conference mode (line \the\inputlineno).}\fi\global\@IEEEWARNIEEEaftertitletextfalse} +\fi + + +% provide a way to restore the commands that are locked out +\def\IEEEoverridecommandlockouts{% +\typeout{** ATTENTION: Overriding command lockouts (line \the\inputlineno).}% +\let\thanks\@IEEESAVECMDthanks% +\let\IEEEPARstart\@IEEESAVECMDIEEEPARstart% +\let\IEEEbiography\@IEEESAVECMDIEEEbiography% +\let\endIEEEbiography\@IEEESAVECMDendIEEEbiography% +\let\IEEEbiographynophoto\@IEEESAVECMDIEEEbiographynophoto% +\let\endIEEEbiographynophoto\@IEEESAVECMDendIEEEbiographynophoto% +\let\IEEEpubid\@IEEESAVECMDIEEEpubid% +\let\IEEEpubidadjcol\@IEEESAVECMDIEEEpubidadjcol% +\let\IEEEmembership\@IEEESAVECMDIEEEmembership% +\let\IEEEaftertitletext\@IEEESAVECMDIEEEaftertitletext} + + + +% need a backslash character for typeout output +{\catcode`\|=0 \catcode`\\=12 +|xdef|@IEEEbackslash{\}} + + +% hook to allow easy disabling of all legacy warnings +\def\@IEEElegacywarn#1#2{\typeout{** ATTENTION: \@IEEEbackslash #1 is deprecated (line \the\inputlineno). +Use \@IEEEbackslash #2 instead.}} + + +% provide for legacy commands +\def\authorblockA{\@IEEElegacywarn{authorblockA}{IEEEauthorblockA}\IEEEauthorblockA} +\def\authorblockN{\@IEEElegacywarn{authorblockN}{IEEEauthorblockN}\IEEEauthorblockN} +\def\authorrefmark{\@IEEElegacywarn{authorrefmark}{IEEEauthorrefmark}\IEEEauthorrefmark} +\def\PARstart{\@IEEElegacywarn{PARstart}{IEEEPARstart}\IEEEPARstart} +\def\pubid{\@IEEElegacywarn{pubid}{IEEEpubid}\IEEEpubid} +\def\pubidadjcol{\@IEEElegacywarn{pubidadjcol}{IEEEpubidadjcol}\IEEEpubidadjcol} +\def\QED{\@IEEElegacywarn{QED}{IEEEQED}\IEEEQED} +\def\QEDclosed{\@IEEElegacywarn{QEDclosed}{IEEEQEDclosed}\IEEEQEDclosed} +\def\QEDopen{\@IEEElegacywarn{QEDopen}{IEEEQEDopen}\IEEEQEDopen} +\def\specialpapernotice{\@IEEElegacywarn{specialpapernotice}{IEEEspecialpapernotice}\IEEEspecialpapernotice} + + + +% provide for legacy environments +\def\biography{\@IEEElegacywarn{biography}{IEEEbiography}\IEEEbiography} +\def\biographynophoto{\@IEEElegacywarn{biographynophoto}{IEEEbiographynophoto}\IEEEbiographynophoto} +\def\keywords{\@IEEElegacywarn{keywords}{IEEEkeywords}\IEEEkeywords} +\def\endbiography{\endIEEEbiography} +\def\endbiographynophoto{\endIEEEbiographynophoto} +\def\endkeywords{\endIEEEkeywords} + + +% provide for legacy IED commands/lengths when possible +\let\labelindent\IEEElabelindent +\def\calcleftmargin{\@IEEElegacywarn{calcleftmargin}{IEEEcalcleftmargin}\IEEEcalcleftmargin} +\def\setlabelwidth{\@IEEElegacywarn{setlabelwidth}{IEEEsetlabelwidth}\IEEEsetlabelwidth} +\def\usemathlabelsep{\@IEEElegacywarn{usemathlabelsep}{IEEEusemathlabelsep}\IEEEusemathlabelsep} +\def\iedlabeljustifyc{\@IEEElegacywarn{iedlabeljustifyc}{IEEEiedlabeljustifyc}\IEEEiedlabeljustifyc} +\def\iedlabeljustifyl{\@IEEElegacywarn{iedlabeljustifyl}{IEEEiedlabeljustifyl}\IEEEiedlabeljustifyl} +\def\iedlabeljustifyr{\@IEEElegacywarn{iedlabeljustifyr}{IEEEiedlabeljustifyr}\IEEEiedlabeljustifyr} + + + +% let \proof use the IEEEtran version even after amsthm is loaded +% \proof is now deprecated in favor of \IEEEproof +\AtBeginDocument{\def\proof{\@IEEElegacywarn{proof}{IEEEproof}\IEEEproof}\def\endproof{\endIEEEproof}} + +% V1.7 \overrideIEEEmargins is no longer supported. +\def\overrideIEEEmargins{% +\typeout{** WARNING: \string\overrideIEEEmargins \space no longer supported (line \the\inputlineno).}% +\typeout{** Use the \string\CLASSINPUTinnersidemargin, \string\CLASSINPUToutersidemargin \space controls instead.}} + + +\endinput + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% End of IEEEtran.cls %%%%%%%%%%%%%%%%%%%%%%%%%%%% +% That's all folks! + diff --git a/doc/IEEEtrantools.sty b/doc/IEEEtrantools.sty new file mode 100644 index 0000000000000000000000000000000000000000..76ce3930c0758dc16559b07a87e4b41698960199 --- /dev/null +++ b/doc/IEEEtrantools.sty @@ -0,0 +1,1858 @@ +%% +%% IEEEtrantools.sty 2007/01/11 version V1.2 +%% +%% +%% This package provides several popular and unique commands from the +%% IEEEtran.cls class (version 1.7) file. +%% +%% The provided commands include \IEEEPARstart, \IEEEitemize, \IEEEenumerate, +%% \IEEEdescription as well as the \IEEEeqnarray, \IEEEeqnarraybox family +%% of commands including support commands such as \IEEEstrut. +%% Also provides the \bstctlcite command for the control entry types of +%% IEEEtran.bst V1.00 and later. +%% +%% IEEEtrantools.sty should not be used with IEEEtran.cls. +%% +%% Support sites: +%% http://www.michaelshell.org/tex/ieeetran/ +%% http://www.ctan.org/tex-archive/macros/latex/contrib/IEEEtran/ +%% +%% +%% Copyright (c) 2002-2007 by Michael Shell +%% See: http://www.michaelshell.org/ +%% for current contact information. +%% +%%************************************************************************* +%% Legal Notice: +%% This code is offered as-is without any warranty either expressed or +%% implied; without even the implied warranty of MERCHANTABILITY or +%% FITNESS FOR A PARTICULAR PURPOSE! +%% User assumes all risk. +%% In no event shall IEEE or any contributor to this code be liable for +%% any damages or losses, including, but not limited to, incidental, +%% consequential, or any other damages, resulting from the use or misuse +%% of any information contained here. +%% +%% All comments are the opinions of their respective authors and are not +%% necessarily endorsed by the IEEE. +%% +%% This work is distributed under the LaTeX Project Public License (LPPL) +%% ( http://www.latex-project.org/ ) version 1.3, and may be freely used, +%% distributed and modified. A copy of the LPPL, version 1.3, is included +%% in the base LaTeX documentation of all distributions of LaTeX released +%% 2003/12/01 or later. +%% Retain all contribution notices and credits. +%% ** Modified files should be clearly indicated as such, including ** +%% ** renaming them and changing author support contact information. ** +%% +%% File list of work: IEEEtrantools.sty, IEEEtrantools_doc.txt +%%************************************************************************* +%% +%% +%% +%% Available package options (e.g., \usepackage[retainorgcmds]{IEEEtrantools} +%% +%% retainorgcmds +%% Prevents IEEEtrantools from overriding existing LaTeX commands. +%% Currently, the only effect is to preserve the original definitions +%% of itemize, enumerate and description. The IEEEtran versions are +%% always available as IEEEitemize, IEEEenumerate and IEEEdescription. +%% +%%******* +% 1/2007 V1.2 (V1.7 of IEEEtran.cls) changes: +% +% 1) Several commands and environments have depreciated in favor of +% replacements with IEEE prefixes to better avoid potential future name +% clashes with other packages. Legacy code retained to allow +% use of the obsolete forms, but with an warning message to the +% console during compilation: +% \IEEEPARstart +% For IED lists: +% \IEEEiedlabeljustifyc, \IEEEiedlabeljustifyl, \IEEEiedlabeljustifyr, +% \IEEEnocalcleftmargin, \IEEElabelindent, \IEEEsetlabelwidth, +% \IEEEusemathlabelsep +% +% 2) These commands/lengths now require the IEEE prefix and do not have +% legacy support: \IEEEnormaljot. +% For IED lists: \ifIEEEnocalcleftmargin, \ifIEEEnolabelindentfactor, +% \IEEEiedlistdecl, \IEEElabelindentfactor +% +% 3) \normalsizebaselineskip no longer provided. +% +% 4) New \IEEEPARstart controls: +% \IEEEPARstartHEIGHTTEXT, \IEEEPARstartFONTSTYLE, \IEEEPARstartCAPSTYLE, +% \IEEEPARstartWORDFONTSTYLE, \IEEEPARstartWORDCAPSTYLE, +% \IEEEPARstartHOFFSET, \IEEEPARstartITLCORRECT +% and the (output) length \IEEEPARstartletwidth. +% +% 5) Provide for an optional argument to \bstctlcite to provide a way to +% specify a different aux file. +% +% +% 11/2002 V1.1 (V1.6b of IEEEtran.cls) changes: +% +% 1) In addition to the IEEE IED lists, the original LaTeX IED style list +% environments are now preserved as LaTeXitemize, LaTeXenumerate, and +% LaTeXdescription. Also, users can now redefine \makelabel within +% IEEE IED list controls. There may be some use for these in specialized +% applications. Thanks to Eli Barzilay for suggesting this feature. +% +%%********************************************************************** + + +\ProvidesPackage{IEEEtrantools}[2007/01/11 V1.2 by Michael Shell] +\typeout{-- See the "IEEEtrantools_doc.txt" manual for usage information.} +\typeout{-- http://www.michaelshell.org/tex/ieeetran/tools/} +\NeedsTeXFormat{LaTeX2e} + + +% If IEEEtran.cls is detected, error. +{\@ifundefined{IEEEtransversionmajor}{\relax}{% +\PackageError{IEEEtrantools}{IEEEtrantools is not for use with the\MessageBreak + IEEEtran class}% + {Do not load IEEEtrantools - you don't need it.}% +}} + + +% define new needed flags to indicate document options +% and set a few "failsafe" defaults +\newif\if@IEEETOOLSretainorgcmds +\global\@IEEETOOLSretainorgcmdsfalse + + + +% IEEEtran class scratch pad registers +% dimen +\newdimen\@IEEEtrantmpdimenA +\newdimen\@IEEEtrantmpdimenB +% count +\newcount\@IEEEtrantmpcountA +\newcount\@IEEEtrantmpcountB +% token list +\newtoks\@IEEEtrantmptoksA + + +% declare the options +\DeclareOption{retainorgcmds}{\@IEEETOOLSretainorgcmdstrue} + +% get and process any supplied options +\ProcessOptions + + + +% store the nominal value of jot +\newdimen\IEEEnormaljot +\IEEEnormaljot\jot\relax + + +% Itemize, Enumerate and Description (IED) List Controls +% *************************** +% +% +% IEEE seems to use at least two different values by +% which ITEMIZED list labels are indented to the right +% For The Journal of Lightwave Technology (JLT) and The Journal +% on Selected Areas in Communications (JSAC), they tend to use +% an indention equal to \parindent. For Transactions on Communications +% they tend to indent ITEMIZED lists a little more--- 1.3\parindent. +% We'll provide both values here for you so that you can choose +% which one you like in your document using a command such as: +% setlength{\IEEEilabelindent}{\IEEEilabelindentB} +\newdimen\IEEEilabelindentA +\IEEEilabelindentA \parindent + +\newdimen\IEEEilabelindentB +\IEEEilabelindentB 1.3\parindent +% However, we'll default to using \parindent +% which makes more sense to me +\newdimen\IEEEilabelindent +\IEEEilabelindent \IEEEilabelindentA + + +% This controls the default amount the enumerated list labels +% are indented to the right. +% Normally, this is the same as the paragraph indention +\newdimen\IEEEelabelindent +\IEEEelabelindent \parindent + +% This controls the default amount the description list labels +% are indented to the right. +% Normally, this is the same as the paragraph indention +\newdimen\IEEEdlabelindent +\IEEEdlabelindent \parindent + +% This is the value actually used within the IED lists. +% The IED environments automatically set its value to +% one of the three values above, so global changes do +% not have any effect +\newdimen\IEEElabelindent +\IEEElabelindent \parindent + +% The actual amount labels will be indented is +% \IEEElabelindent multiplied by the factor below +% corresponding to the level of nesting depth +% This provides a means by which the user can +% alter the effective \IEEElabelindent for deeper +% levels +% There may not be such a thing as correct "standard IEEE" +% values. What IEEE actually does may depend on the specific +% circumstances. +% The first list level almost always has full indention. +% The second levels I've seen have only 75% of the normal indentation +% Three level or greater nestings are very rare. I am guessing +% that they don't use any indentation. +\def\IEEElabelindentfactori{1.0} % almost always one +\def\IEEElabelindentfactorii{0.75} % 0.0 or 1.0 may be used in some cases +\def\IEEElabelindentfactoriii{0.0} % 0.75? 0.5? 0.0? +\def\IEEElabelindentfactoriv{0.0} +\def\IEEElabelindentfactorv{0.0} +\def\IEEElabelindentfactorvi{0.0} + +% value actually used within IED lists, it is auto +% set to one of the 6 values above +% global changes here have no effect +\def\IEEElabelindentfactor{1.0} + +% This controls the default spacing between the end of the IED +% list labels and the list text, when normal text is used for +% the labels. +\newdimen\IEEEiednormlabelsep +\IEEEiednormlabelsep 0.6em + +% This controls the default spacing between the end of the IED +% list labels and the list text, when math symbols are used for +% the labels (nomenclature lists). IEEE usually increases the +% spacing in these cases +\newdimen\IEEEiedmathlabelsep +\IEEEiedmathlabelsep 1.2em + +% This controls the extra vertical separation put above and +% below each IED list. IEEE usually puts a little extra spacing +% around each list. However, this spacing is barely noticeable. +\newskip\IEEEiedtopsep +\IEEEiedtopsep 2pt plus 1pt minus 1pt + + +% This command is executed within each IED list environment +% at the beginning of the list. You can use this to set the +% parameters for some/all your IED list(s) without disturbing +% global parameters that affect things other than lists. +% i.e., renewcommand{\IEEEiedlistdecl}{\setlength{\labelsep}{5em}} +% will alter the \labelsep for the next list(s) until +% \IEEEiedlistdecl is redefined. +\def\IEEEiedlistdecl{\relax} + +% This command provides an easy way to set \leftmargin based +% on the \labelwidth, \labelsep and the argument \IEEElabelindent +% Usage: \IEEEcalcleftmargin{width-to-indent-the-label} +% output is in the \leftmargin variable, i.e., effectively: +% \leftmargin = argument + \labelwidth + \labelsep +% Note controlled spacing here, shield end of lines with % +\def\IEEEcalcleftmargin#1{\setlength{\leftmargin}{#1}% +\addtolength{\leftmargin}{\labelwidth}% +\addtolength{\leftmargin}{\labelsep}} + +% This command provides an easy way to set \labelwidth to the +% width of the given text. It is the same as +% \settowidth{\labelwidth}{label-text} +% and useful as a shorter alternative. +% Typically used to set \labelwidth to be the width +% of the longest label in the list +\def\IEEEsetlabelwidth#1{\settowidth{\labelwidth}{#1}} + +% When this command is executed, IED lists will use the +% IEEEiedmathlabelsep label separation rather than the normal +% spacing. To have an effect, this command must be executed via +% the \IEEEiedlistdecl or within the option of the IED list +% environments. +\def\IEEEusemathlabelsep{\setlength{\labelsep}{\IEEEiedmathlabelsep}} + +% A flag which controls whether the IED lists automatically +% calculate \leftmargin from \IEEElabelindent, \labelwidth and \labelsep +% Useful if you want to specify your own \leftmargin +% This flag must be set (\IEEEnocalcleftmargintrue or \IEEEnocalcleftmarginfalse) +% via the \IEEEiedlistdecl or within the option of the IED list +% environments to have an effect. +\newif\ifIEEEnocalcleftmargin +\IEEEnocalcleftmarginfalse + +% A flag which controls whether \IEEElabelindent is multiplied by +% the \IEEElabelindentfactor for each list level. +% This flag must be set via the \IEEEiedlistdecl or within the option +% of the IED list environments to have an effect. +\newif\ifIEEEnolabelindentfactor +\IEEEnolabelindentfactorfalse + + +% internal variable to indicate type of IED label +% justification +% 0 - left; 1 - center; 2 - right +\def\@IEEEiedjustify{0} + + + +% commands to allow the user to control IED +% label justifications. Use these commands within +% the IED environment option or in the \IEEEiedlistdecl +% Note that changing the normal list justifications +% is nonstandard and IEEE may not like it if you do so! +% I include these commands as they may be helpful to +% those who are using these enhanced list controls for +% other non-IEEE related LaTeX work. +% itemize and enumerate automatically default to right +% justification, description defaults to left. +\def\IEEEiedlabeljustifyl{\def\@IEEEiedjustify{0}}%left +\def\IEEEiedlabeljustifyc{\def\@IEEEiedjustify{1}}%center +\def\IEEEiedlabeljustifyr{\def\@IEEEiedjustify{2}}%right + + + + +% commands to save to and restore from the list parameter copies +% this allows us to set all the list parameters within +% the list_decl and prevent \list (and its \@list) +% from overriding any of our parameters +% V1.6 use \edefs instead of dimen's to conserve dimen registers +% Note controlled spacing here, shield end of lines with % +\def\@IEEEsavelistparams{\edef\@IEEEiedtopsep{\the\topsep}% +\edef\@IEEEiedlabelwidth{\the\labelwidth}% +\edef\@IEEEiedlabelsep{\the\labelsep}% +\edef\@IEEEiedleftmargin{\the\leftmargin}% +\edef\@IEEEiedpartopsep{\the\partopsep}% +\edef\@IEEEiedparsep{\the\parsep}% +\edef\@IEEEieditemsep{\the\itemsep}% +\edef\@IEEEiedrightmargin{\the\rightmargin}% +\edef\@IEEEiedlistparindent{\the\listparindent}% +\edef\@IEEEieditemindent{\the\itemindent}} + +% Note controlled spacing here +\def\@IEEErestorelistparams{\topsep\@IEEEiedtopsep\relax% +\labelwidth\@IEEEiedlabelwidth\relax% +\labelsep\@IEEEiedlabelsep\relax% +\leftmargin\@IEEEiedleftmargin\relax% +\partopsep\@IEEEiedpartopsep\relax% +\parsep\@IEEEiedparsep\relax% +\itemsep\@IEEEieditemsep\relax% +\rightmargin\@IEEEiedrightmargin\relax% +\listparindent\@IEEEiedlistparindent\relax% +\itemindent\@IEEEieditemindent\relax} + + +% v1.6b provide original LaTeX IED list environments +% note that latex.ltx defines \itemize and \enumerate, but not \description +% which must be created by the base classes +% save original LaTeX itemize and enumerate +\let\LaTeXitemize\itemize +\let\endLaTeXitemize\enditemize +\let\LaTeXenumerate\enumerate +\let\endLaTeXenumerate\endenumerate +% base class should define \description +\let\LaTeXdescription\description +\let\endLaTeXdescription\enddescription + + +% override LaTeX's default IED lists, unless the user requested they be retained +\if@IEEETOOLSretainorgcmds\relax\else +\def\itemize{\@IEEEitemize} +\def\enditemize{\@endIEEEitemize} +\def\enumerate{\@IEEEenumerate} +\def\endenumerate{\@endIEEEenumerate} +\def\description{\@IEEEdescription} +\def\enddescription{\@endIEEEdescription} +\fi + + +% provide the user with the IEEE IED commands +\def\IEEEitemize{\@IEEEitemize} +\def\endIEEEitemize{\@endIEEEitemize} +\def\IEEEenumerate{\@IEEEenumerate} +\def\endIEEEenumerate{\@endIEEEenumerate} +\def\IEEEdescription{\@IEEEdescription} +\def\endIEEEdescription{\@endIEEEdescription} + + +% V1.6 we want to keep the IEEEtran IED list definitions as our own internal +% commands so they are protected against redefinition +\def\@IEEEitemize{\@ifnextchar[{\@@IEEEitemize}{\@@IEEEitemize[\relax]}} +\def\@IEEEenumerate{\@ifnextchar[{\@@IEEEenumerate}{\@@IEEEenumerate[\relax]}} +\def\@IEEEdescription{\@ifnextchar[{\@@IEEEdescription}{\@@IEEEdescription[\relax]}} +\def\@endIEEEitemize{\endlist} +\def\@endIEEEenumerate{\endlist} +\def\@endIEEEdescription{\endlist} + + +% DO NOT ALLOW BLANK LINES TO BE IN THESE IED ENVIRONMENTS +% AS THIS WILL FORCE NEW PARAGRAPHS AFTER THE IED LISTS +% IEEEtran itemized list MDS 1/2001 +% Note controlled spacing here, shield end of lines with % +\def\@@IEEEitemize[#1]{% + \ifnum\@itemdepth>3\relax\@toodeep\else% + \ifnum\@listdepth>5\relax\@toodeep\else% + \advance\@itemdepth\@ne% + \edef\@itemitem{labelitem\romannumeral\the\@itemdepth}% + % get the labelindentfactor for this level + \advance\@listdepth\@ne% we need to know what the level WILL be + \edef\IEEElabelindentfactor{\csname IEEElabelindentfactor\romannumeral\the\@listdepth\endcsname}% + \advance\@listdepth-\@ne% undo our increment + \def\@IEEEiedjustify{2}% right justified labels are default + % set other defaults + \IEEEnocalcleftmarginfalse% + \IEEEnolabelindentfactorfalse% + \topsep\IEEEiedtopsep% + \IEEElabelindent\IEEEilabelindent% + \labelsep\IEEEiednormlabelsep% + \partopsep 0ex% + \parsep 0ex% + \itemsep 0ex% + \rightmargin 0em% + \listparindent 0em% + \itemindent 0em% + % calculate the label width + % the user can override this later if + % they specified a \labelwidth + \settowidth{\labelwidth}{\csname labelitem\romannumeral\the\@itemdepth\endcsname}% + \@IEEEsavelistparams% save our list parameters + \list{\csname\@itemitem\endcsname}{% + \@IEEErestorelistparams% override any list{} changes + % to our globals + \let\makelabel\@IEEEiedmakelabel% v1.6b setup \makelabel + \IEEEiedlistdecl% let user alter parameters + #1\relax% + % If the user has requested not to use the + % labelindent factor, don't revise \labelindent + \ifIEEEnolabelindentfactor\relax% + \else\IEEElabelindent=\IEEElabelindentfactor\labelindent% + \fi% + % Unless the user has requested otherwise, + % calculate our left margin based + % on \IEEElabelindent, \labelwidth and + % \labelsep + \ifIEEEnocalcleftmargin\relax% + \else\IEEEcalcleftmargin{\IEEElabelindent}% + \fi}\fi\fi}% + + +% DO NOT ALLOW BLANK LINES TO BE IN THESE IED ENVIRONMENTS +% AS THIS WILL FORCE NEW PARAGRAPHS AFTER THE IED LISTS +% IEEEtran enumerate list MDS 1/2001 +% Note controlled spacing here, shield end of lines with % +\def\@@IEEEenumerate[#1]{% + \ifnum\@enumdepth>3\relax\@toodeep\else% + \ifnum\@listdepth>5\relax\@toodeep\else% + \advance\@enumdepth\@ne% + \edef\@enumctr{enum\romannumeral\the\@enumdepth}% + % get the labelindentfactor for this level + \advance\@listdepth\@ne% we need to know what the level WILL be + \edef\IEEElabelindentfactor{\csname IEEElabelindentfactor\romannumeral\the\@listdepth\endcsname}% + \advance\@listdepth-\@ne% undo our increment + \def\@IEEEiedjustify{2}% right justified labels are default + % set other defaults + \IEEEnocalcleftmarginfalse% + \IEEEnolabelindentfactorfalse% + \topsep\IEEEiedtopsep% + \IEEElabelindent\IEEEelabelindent% + \labelsep\IEEEiednormlabelsep% + \partopsep 0ex% + \parsep 0ex% + \itemsep 0ex% + \rightmargin 0em% + \listparindent 0em% + \itemindent 0em% + % calculate the label width + % We'll set it to the width suitable for all labels using + % normalfont 1) to 9) + % The user can override this later + \settowidth{\labelwidth}{9)}% + \@IEEEsavelistparams% save our list parameters + \list{\csname label\@enumctr\endcsname}{\usecounter{\@enumctr}% + \@IEEErestorelistparams% override any list{} changes + % to our globals + \let\makelabel\@IEEEiedmakelabel% v1.6b setup \makelabel + \IEEEiedlistdecl% let user alter parameters + #1\relax% + % If the user has requested not to use the + % IEEElabelindent factor, don't revise \IEEElabelindent + \ifIEEEnolabelindentfactor\relax% + \else\IEEElabelindent=\IEEElabelindentfactor\IEEElabelindent% + \fi% + % Unless the user has requested otherwise, + % calculate our left margin based + % on \IEEElabelindent, \labelwidth and + % \labelsep + \ifIEEEnocalcleftmargin\relax% + \else\IEEEcalcleftmargin{\IEEElabelindent}% + \fi}\fi\fi}% + + +% DO NOT ALLOW BLANK LINES TO BE IN THESE IED ENVIRONMENTS +% AS THIS WILL FORCE NEW PARAGRAPHS AFTER THE IED LISTS +% IEEEtran description list MDS 1/2001 +% Note controlled spacing here, shield end of lines with % +\def\@@IEEEdescription[#1]{% + \ifnum\@listdepth>5\relax\@toodeep\else% + % get the labelindentfactor for this level + \advance\@listdepth\@ne% we need to know what the level WILL be + \edef\IEEElabelindentfactor{\csname IEEElabelindentfactor\romannumeral\the\@listdepth\endcsname}% + \advance\@listdepth-\@ne% undo our increment + \def\@IEEEiedjustify{0}% left justified labels are default + % set other defaults + \IEEEnocalcleftmarginfalse% + \IEEEnolabelindentfactorfalse% + \topsep\IEEEiedtopsep% + \IEEElabelindent\IEEEdlabelindent% + % assume normal labelsep + \labelsep\IEEEiednormlabelsep% + \partopsep 0ex% + \parsep 0ex% + \itemsep 0ex% + \rightmargin 0em% + \listparindent 0em% + \itemindent 0em% + % Bogus label width in case the user forgets + % to set it. + % TIP: If you want to see what a variable's width is you + % can use the TeX command \showthe\width-variable to + % display it on the screen during compilation + % (This might be helpful to know when you need to find out + % which label is the widest) + \settowidth{\labelwidth}{Hello}% + \@IEEEsavelistparams% save our list parameters + \list{}{\@IEEErestorelistparams% override any list{} changes + % to our globals + \let\makelabel\@IEEEiedmakelabel% v1.6b setup \makelabel + \IEEEiedlistdecl% let user alter parameters + #1\relax% + % If the user has requested not to use the + % labelindent factor, don't revise \IEEElabelindent + \ifIEEEnolabelindentfactor\relax% + \else\IEEElabelindent=\IEEElabelindentfactor\IEEElabelindent% + \fi% + % Unless the user has requested otherwise, + % calculate our left margin based + % on \IEEElabelindent, \labelwidth and + % \labelsep + \ifIEEEnocalcleftmargin\relax% + \else\IEEEcalcleftmargin{\IEEElabelindent}\relax% + \fi}\fi} + +% v1.6b we use one makelabel that does justification as needed. +\def\@IEEEiedmakelabel#1{\relax\if\@IEEEiedjustify 0\relax +\makebox[\labelwidth][l]{\normalfont #1}\else +\if\@IEEEiedjustify 1\relax +\makebox[\labelwidth][c]{\normalfont #1}\else +\makebox[\labelwidth][r]{\normalfont #1}\fi\fi} + + + + + + + + + +% used only by IEEEtran's IEEEeqnarray as other packages may +% have their own, different, implementations +\newcounter{IEEEsubequation}[equation] + +% e.g., "1a" (used only by IEEEtran's IEEEeqnarray) +\def\theIEEEsubequation{\theequation\alph{IEEEsubequation}} +% just like LaTeX2e's \@eqnnum +\def\theequationdis{{\normalfont \normalcolor (\theequation)}}% (1) +% IEEEsubequation used only by IEEEtran's IEEEeqnarray +\def\theIEEEsubequationdis{{\normalfont \normalcolor (\theIEEEsubequation)}}% (1a) + + + + +%% +%% START OF IEEEeqnarry DEFINITIONS +%% +%% Inspired by the concepts, examples, and previous works of LaTeX +%% coders and developers such as Donald Arseneau, Fred Bartlett, +%% David Carlisle, Tony Liu, Frank Mittelbach, Piet van Oostrum, +%% Roland Winkler and Mark Wooding. +%% I don't make the claim that my work here is even near their calibre. ;) + + +% hook to allow easy changeover to IEEEtran.cls/tools.sty error reporting +\def\@IEEEclspkgerror{\PackageError{IEEEtran}} + +\newif\if@IEEEeqnarraystarform% flag to indicate if the environment was called as the star form +\@IEEEeqnarraystarformfalse + +\newif\if@advanceIEEEeqncolcnt% tracks if the environment should advance the col counter +% allows a way to make an \IEEEeqnarraybox that can be used within an \IEEEeqnarray +% used by IEEEeqnarraymulticol so that it can work properly in both +\@advanceIEEEeqncolcnttrue + +\newcount\@IEEEeqnnumcols % tracks how many IEEEeqnarray cols are defined +\newcount\@IEEEeqncolcnt % tracks how many IEEEeqnarray cols the user actually used + + +% The default math style used by the columns +\def\IEEEeqnarraymathstyle{\displaystyle} +% The default text style used by the columns +% default to using the current font +\def\IEEEeqnarraytextstyle{\relax} + +% like the iedlistdecl but for \IEEEeqnarray +\def\IEEEeqnarraydecl{\relax} +\def\IEEEeqnarrayboxdecl{\relax} + +% \yesnumber is the opposite of \nonumber +% a novel concept with the same def as the equationarray package +% However, we give IEEE versions too since some LaTeX packages such as +% the MDWtools mathenv.sty redefine \nonumber to something else. +\providecommand{\yesnumber}{\global\@eqnswtrue} +\def\IEEEyesnumber{\global\@eqnswtrue} +\def\IEEEnonumber{\global\@eqnswfalse} + + +\def\IEEEyessubnumber{\global\@IEEEissubequationtrue\global\@eqnswtrue% +\if@IEEEeqnarrayISinner% only do something inside an IEEEeqnarray +\if@IEEElastlinewassubequation\addtocounter{equation}{-1}\else\setcounter{IEEEsubequation}{1}\fi% +\def\@currentlabel{\p@IEEEsubequation\theIEEEsubequation}\fi} + +% flag to indicate that an equation is a sub equation +\newif\if@IEEEissubequation% +\@IEEEissubequationfalse + +% allows users to "push away" equations that get too close to the equation numbers +\def\IEEEeqnarraynumspace{\hphantom{\if@IEEEissubequation\theIEEEsubequationdis\else\theequationdis\fi}} + +% provides a way to span multiple columns within IEEEeqnarray environments +% will consider \if@advanceIEEEeqncolcnt before globally advancing the +% column counter - so as to work within \IEEEeqnarraybox +% usage: \IEEEeqnarraymulticol{number cols. to span}{col type}{cell text} +\long\def\IEEEeqnarraymulticol#1#2#3{\multispan{#1}% +% check if column is defined +\relax\expandafter\ifx\csname @IEEEeqnarraycolDEF#2\endcsname\@IEEEeqnarraycolisdefined% +\csname @IEEEeqnarraycolPRE#2\endcsname#3\relax\relax\relax\relax\relax% +\relax\relax\relax\relax\relax\csname @IEEEeqnarraycolPOST#2\endcsname% +\else% if not, error and use default type +\@IEEEclspkgerror{Invalid column type "#2" in \string\IEEEeqnarraymulticol.\MessageBreak +Using a default centering column instead}% +{You must define IEEEeqnarray column types before use.}% +\csname @IEEEeqnarraycolPRE@IEEEdefault\endcsname#3\relax\relax\relax\relax\relax% +\relax\relax\relax\relax\relax\csname @IEEEeqnarraycolPOST@IEEEdefault\endcsname% +\fi% +% advance column counter only if the IEEEeqnarray environment wants it +\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by #1\relax\fi} + +% like \omit, but maintains track of the column counter for \IEEEeqnarray +\def\IEEEeqnarrayomit{\omit\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by 1\relax\fi} + + +% provides a way to define a letter referenced column type +% usage: \IEEEeqnarraydefcol{col. type letter/name}{pre insertion text}{post insertion text} +\def\IEEEeqnarraydefcol#1#2#3{\expandafter\def\csname @IEEEeqnarraycolPRE#1\endcsname{#2}% +\expandafter\def\csname @IEEEeqnarraycolPOST#1\endcsname{#3}% +\expandafter\def\csname @IEEEeqnarraycolDEF#1\endcsname{1}} + + +% provides a way to define a numerically referenced inter-column glue types +% usage: \IEEEeqnarraydefcolsep{col. glue number}{glue definition} +\def\IEEEeqnarraydefcolsep#1#2{\expandafter\def\csname @IEEEeqnarraycolSEP\romannumeral #1\endcsname{#2}% +\expandafter\def\csname @IEEEeqnarraycolSEPDEF\romannumeral #1\endcsname{1}} + + +\def\@IEEEeqnarraycolisdefined{1}% just a macro for 1, used for checking undefined column types + + +% expands and appends the given argument to the \@IEEEtrantmptoksA token list +% used to build up the \halign preamble +\def\@IEEEappendtoksA#1{\edef\@@IEEEappendtoksA{\@IEEEtrantmptoksA={\the\@IEEEtrantmptoksA #1}}% +\@@IEEEappendtoksA} + +% also appends to \@IEEEtrantmptoksA, but does not expand the argument +% uses \toks8 as a scratchpad register +\def\@IEEEappendNOEXPANDtoksA#1{\toks8={#1}% +\edef\@@IEEEappendNOEXPANDtoksA{\@IEEEtrantmptoksA={\the\@IEEEtrantmptoksA\the\toks8}}% +\@@IEEEappendNOEXPANDtoksA} + +% define some common column types for the user +% math +\IEEEeqnarraydefcol{l}{$\IEEEeqnarraymathstyle}{$\hfil} +\IEEEeqnarraydefcol{c}{\hfil$\IEEEeqnarraymathstyle}{$\hfil} +\IEEEeqnarraydefcol{r}{\hfil$\IEEEeqnarraymathstyle}{$} +\IEEEeqnarraydefcol{L}{$\IEEEeqnarraymathstyle{}}{{}$\hfil} +\IEEEeqnarraydefcol{C}{\hfil$\IEEEeqnarraymathstyle{}}{{}$\hfil} +\IEEEeqnarraydefcol{R}{\hfil$\IEEEeqnarraymathstyle{}}{{}$} +% text +\IEEEeqnarraydefcol{s}{\IEEEeqnarraytextstyle}{\hfil} +\IEEEeqnarraydefcol{t}{\hfil\IEEEeqnarraytextstyle}{\hfil} +\IEEEeqnarraydefcol{u}{\hfil\IEEEeqnarraytextstyle}{} + +% vertical rules +\IEEEeqnarraydefcol{v}{}{\vrule width\arrayrulewidth} +\IEEEeqnarraydefcol{vv}{\vrule width\arrayrulewidth\hfil}{\hfil\vrule width\arrayrulewidth} +\IEEEeqnarraydefcol{V}{}{\vrule width\arrayrulewidth\hskip\doublerulesep\vrule width\arrayrulewidth} +\IEEEeqnarraydefcol{VV}{\vrule width\arrayrulewidth\hskip\doublerulesep\vrule width\arrayrulewidth\hfil}% +{\hfil\vrule width\arrayrulewidth\hskip\doublerulesep\vrule width\arrayrulewidth} + +% horizontal rules +\IEEEeqnarraydefcol{h}{}{\leaders\hrule height\arrayrulewidth\hfil} +\IEEEeqnarraydefcol{H}{}{\leaders\vbox{\hrule width\arrayrulewidth\vskip\doublerulesep\hrule width\arrayrulewidth}\hfil} + +% plain +\IEEEeqnarraydefcol{x}{}{} +\IEEEeqnarraydefcol{X}{$}{$} + +% the default column type to use in the event a column type is not defined +\IEEEeqnarraydefcol{@IEEEdefault}{\hfil$\IEEEeqnarraymathstyle}{$\hfil} + + +% a zero tabskip (used for "-" col types) +\def\@IEEEeqnarraycolSEPzero{0pt plus 0pt minus 0pt} +% a centering tabskip (used for "+" col types) +\def\@IEEEeqnarraycolSEPcenter{1000pt plus 0pt minus 1000pt} + +% top level default tabskip glues for the start, end, and inter-column +% may be reset within environments not always at the top level, e.g., \IEEEeqnarraybox +\edef\@IEEEeqnarraycolSEPdefaultstart{\@IEEEeqnarraycolSEPcenter}% default start glue +\edef\@IEEEeqnarraycolSEPdefaultend{\@IEEEeqnarraycolSEPcenter}% default end glue +\edef\@IEEEeqnarraycolSEPdefaultmid{\@IEEEeqnarraycolSEPzero}% default inter-column glue + + + +% creates a vertical rule that extends from the bottom to the top a a cell +% Provided in case other packages redefine \vline some other way. +% usage: \IEEEeqnarrayvrule[rule thickness] +% If no argument is provided, \arrayrulewidth will be used for the rule thickness. +\newcommand\IEEEeqnarrayvrule[1][\arrayrulewidth]{\vrule\@width#1\relax} + +% creates a blank separator row +% usage: \IEEEeqnarrayseprow[separation length][font size commands] +% default is \IEEEeqnarrayseprow[0.25\normalbaselineskip][\relax] +% blank arguments inherit the default values +% uses \skip5 as a scratch register - calls \@IEEEeqnarraystrutsize which uses more scratch registers +\def\IEEEeqnarrayseprow{\relax\@ifnextchar[{\@IEEEeqnarrayseprow}{\@IEEEeqnarrayseprow[0.25\normalbaselineskip]}} +\def\@IEEEeqnarrayseprow[#1]{\relax\@ifnextchar[{\@@IEEEeqnarrayseprow[#1]}{\@@IEEEeqnarrayseprow[#1][\relax]}} +\def\@@IEEEeqnarrayseprow[#1][#2]{\def\@IEEEeqnarrayseprowARGONE{#1}% +\ifx\@IEEEeqnarrayseprowARGONE\@empty% +% get the skip value, based on the font commands +% use skip5 because \IEEEeqnarraystrutsize uses \skip0, \skip2, \skip3 +% assign within a bogus box to confine the font changes +{\setbox0=\hbox{#2\relax\global\skip5=0.25\normalbaselineskip}}% +\else% +{\setbox0=\hbox{#2\relax\global\skip5=#1}}% +\fi% +\@IEEEeqnarrayhoptolastcolumn\IEEEeqnarraystrutsize{\skip5}{0pt}[\relax]\relax} + +% creates a blank separator row, but omits all the column templates +% usage: \IEEEeqnarrayseprowcut[separation length][font size commands] +% default is \IEEEeqnarrayseprowcut[0.25\normalbaselineskip][\relax] +% blank arguments inherit the default values +% uses \skip5 as a scratch register - calls \@IEEEeqnarraystrutsize which uses more scratch registers +\def\IEEEeqnarrayseprowcut{\multispan{\@IEEEeqnnumcols}\relax% span all the cols +% advance column counter only if the IEEEeqnarray environment wants it +\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by \@IEEEeqnnumcols\relax\fi% +\@ifnextchar[{\@IEEEeqnarrayseprowcut}{\@IEEEeqnarrayseprowcut[0.25\normalbaselineskip]}} +\def\@IEEEeqnarrayseprowcut[#1]{\relax\@ifnextchar[{\@@IEEEeqnarrayseprowcut[#1]}{\@@IEEEeqnarrayseprowcut[#1][\relax]}} +\def\@@IEEEeqnarrayseprowcut[#1][#2]{\def\@IEEEeqnarrayseprowARGONE{#1}% +\ifx\@IEEEeqnarrayseprowARGONE\@empty% +% get the skip value, based on the font commands +% use skip5 because \IEEEeqnarraystrutsize uses \skip0, \skip2, \skip3 +% assign within a bogus box to confine the font changes +{\setbox0=\hbox{#2\relax\global\skip5=0.25\normalbaselineskip}}% +\else% +{\setbox0=\hbox{#2\relax\global\skip5=#1}}% +\fi% +\IEEEeqnarraystrutsize{\skip5}{0pt}[\relax]\relax} + + + +% draws a single rule across all the columns optional +% argument determines the rule width, \arrayrulewidth is the default +% updates column counter as needed and turns off struts +% usage: \IEEEeqnarrayrulerow[rule line thickness] +\def\IEEEeqnarrayrulerow{\multispan{\@IEEEeqnnumcols}\relax% span all the cols +% advance column counter only if the IEEEeqnarray environment wants it +\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by \@IEEEeqnnumcols\relax\fi% +\@ifnextchar[{\@IEEEeqnarrayrulerow}{\@IEEEeqnarrayrulerow[\arrayrulewidth]}} +\def\@IEEEeqnarrayrulerow[#1]{\leaders\hrule height#1\hfil\relax% put in our rule +% turn off any struts +\IEEEeqnarraystrutsize{0pt}{0pt}[\relax]\relax} + + +% draws a double rule by using a single rule row, a separator row, and then +% another single rule row +% first optional argument determines the rule thicknesses, \arrayrulewidth is the default +% second optional argument determines the rule spacing, \doublerulesep is the default +% usage: \IEEEeqnarraydblrulerow[rule line thickness][rule spacing] +\def\IEEEeqnarraydblrulerow{\multispan{\@IEEEeqnnumcols}\relax% span all the cols +% advance column counter only if the IEEEeqnarray environment wants it +\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by \@IEEEeqnnumcols\relax\fi% +\@ifnextchar[{\@IEEEeqnarraydblrulerow}{\@IEEEeqnarraydblrulerow[\arrayrulewidth]}} +\def\@IEEEeqnarraydblrulerow[#1]{\relax\@ifnextchar[{\@@IEEEeqnarraydblrulerow[#1]}% +{\@@IEEEeqnarraydblrulerow[#1][\doublerulesep]}} +\def\@@IEEEeqnarraydblrulerow[#1][#2]{\def\@IEEEeqnarraydblrulerowARG{#1}% +% we allow the user to say \IEEEeqnarraydblrulerow[][] +\ifx\@IEEEeqnarraydblrulerowARG\@empty% +\@IEEEeqnarrayrulerow[\arrayrulewidth]% +\else% +\@IEEEeqnarrayrulerow[#1]\relax% +\fi% +\def\@IEEEeqnarraydblrulerowARG{#2}% +\ifx\@IEEEeqnarraydblrulerowARG\@empty% +\\\IEEEeqnarrayseprow[\doublerulesep][\relax]% +\else% +\\\IEEEeqnarrayseprow[#2][\relax]% +\fi% +\\\multispan{\@IEEEeqnnumcols}% +% advance column counter only if the IEEEeqnarray environment wants it +\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by \@IEEEeqnnumcols\relax\fi% +\def\@IEEEeqnarraydblrulerowARG{#1}% +\ifx\@IEEEeqnarraydblrulerowARG\@empty% +\@IEEEeqnarrayrulerow[\arrayrulewidth]% +\else% +\@IEEEeqnarrayrulerow[#1]% +\fi% +} + +% draws a double rule by using a single rule row, a separator (cutting) row, and then +% another single rule row +% first optional argument determines the rule thicknesses, \arrayrulewidth is the default +% second optional argument determines the rule spacing, \doublerulesep is the default +% usage: \IEEEeqnarraydblrulerow[rule line thickness][rule spacing] +\def\IEEEeqnarraydblrulerowcut{\multispan{\@IEEEeqnnumcols}\relax% span all the cols +% advance column counter only if the IEEEeqnarray environment wants it +\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by \@IEEEeqnnumcols\relax\fi% +\@ifnextchar[{\@IEEEeqnarraydblrulerowcut}{\@IEEEeqnarraydblrulerowcut[\arrayrulewidth]}} +\def\@IEEEeqnarraydblrulerowcut[#1]{\relax\@ifnextchar[{\@@IEEEeqnarraydblrulerowcut[#1]}% +{\@@IEEEeqnarraydblrulerowcut[#1][\doublerulesep]}} +\def\@@IEEEeqnarraydblrulerowcut[#1][#2]{\def\@IEEEeqnarraydblrulerowARG{#1}% +% we allow the user to say \IEEEeqnarraydblrulerow[][] +\ifx\@IEEEeqnarraydblrulerowARG\@empty% +\@IEEEeqnarrayrulerow[\arrayrulewidth]% +\else% +\@IEEEeqnarrayrulerow[#1]% +\fi% +\def\@IEEEeqnarraydblrulerowARG{#2}% +\ifx\@IEEEeqnarraydblrulerowARG\@empty% +\\\IEEEeqnarrayseprowcut[\doublerulesep][\relax]% +\else% +\\\IEEEeqnarrayseprowcut[#2][\relax]% +\fi% +\\\multispan{\@IEEEeqnnumcols}% +% advance column counter only if the IEEEeqnarray environment wants it +\if@advanceIEEEeqncolcnt\global\advance\@IEEEeqncolcnt by \@IEEEeqnnumcols\relax\fi% +\def\@IEEEeqnarraydblrulerowARG{#1}% +\ifx\@IEEEeqnarraydblrulerowARG\@empty% +\@IEEEeqnarrayrulerow[\arrayrulewidth]% +\else% +\@IEEEeqnarrayrulerow[#1]% +\fi% +} + + + +% inserts a full row's worth of &'s +% relies on \@IEEEeqnnumcols to provide the correct number of columns +% uses \@IEEEtrantmptoksA, \count0 as scratch registers +\def\@IEEEeqnarrayhoptolastcolumn{\@IEEEtrantmptoksA={}\count0=1\relax% +\loop% add cols if the user did not use them all +\ifnum\count0<\@IEEEeqnnumcols\relax% +\@IEEEappendtoksA{&}% +\advance\count0 by 1\relax% update the col count +\repeat% +\the\@IEEEtrantmptoksA%execute the &'s +} + + + +\newif\if@IEEEeqnarrayISinner % flag to indicate if we are within the lines +\@IEEEeqnarrayISinnerfalse % of an IEEEeqnarray - after the IEEEeqnarraydecl + +\edef\@IEEEeqnarrayTHEstrutheight{0pt} % height and depth of IEEEeqnarray struts +\edef\@IEEEeqnarrayTHEstrutdepth{0pt} + +\edef\@IEEEeqnarrayTHEmasterstrutheight{0pt} % default height and depth of +\edef\@IEEEeqnarrayTHEmasterstrutdepth{0pt} % struts within an IEEEeqnarray + +\edef\@IEEEeqnarrayTHEmasterstrutHSAVE{0pt} % saved master strut height +\edef\@IEEEeqnarrayTHEmasterstrutDSAVE{0pt} % and depth + +\newif\if@IEEEeqnarrayusemasterstrut % flag to indicate that the master strut value +\@IEEEeqnarrayusemasterstruttrue % is to be used + + + +% saves the strut height and depth of the master strut +\def\@IEEEeqnarraymasterstrutsave{\relax% +\expandafter\skip0=\@IEEEeqnarrayTHEmasterstrutheight\relax% +\expandafter\skip2=\@IEEEeqnarrayTHEmasterstrutdepth\relax% +% remove stretchability +\dimen0\skip0\relax% +\dimen2\skip2\relax% +% save values +\edef\@IEEEeqnarrayTHEmasterstrutHSAVE{\the\dimen0}% +\edef\@IEEEeqnarrayTHEmasterstrutDSAVE{\the\dimen2}} + +% restores the strut height and depth of the master strut +\def\@IEEEeqnarraymasterstrutrestore{\relax% +\expandafter\skip0=\@IEEEeqnarrayTHEmasterstrutHSAVE\relax% +\expandafter\skip2=\@IEEEeqnarrayTHEmasterstrutDSAVE\relax% +% remove stretchability +\dimen0\skip0\relax% +\dimen2\skip2\relax% +% restore values +\edef\@IEEEeqnarrayTHEmasterstrutheight{\the\dimen0}% +\edef\@IEEEeqnarrayTHEmasterstrutdepth{\the\dimen2}} + + +% globally restores the strut height and depth to the +% master values and sets the master strut flag to true +\def\@IEEEeqnarraystrutreset{\relax% +\expandafter\skip0=\@IEEEeqnarrayTHEmasterstrutheight\relax% +\expandafter\skip2=\@IEEEeqnarrayTHEmasterstrutdepth\relax% +% remove stretchability +\dimen0\skip0\relax% +\dimen2\skip2\relax% +% restore values +\xdef\@IEEEeqnarrayTHEstrutheight{\the\dimen0}% +\xdef\@IEEEeqnarrayTHEstrutdepth{\the\dimen2}% +\global\@IEEEeqnarrayusemasterstruttrue} + + +% if the master strut is not to be used, make the current +% values of \@IEEEeqnarrayTHEstrutheight, \@IEEEeqnarrayTHEstrutdepth +% and the use master strut flag, global +% this allows user strut commands issued in the last column to be carried +% into the isolation/strut column +\def\@IEEEeqnarrayglobalizestrutstatus{\relax% +\if@IEEEeqnarrayusemasterstrut\else% +\xdef\@IEEEeqnarrayTHEstrutheight{\@IEEEeqnarrayTHEstrutheight}% +\xdef\@IEEEeqnarrayTHEstrutdepth{\@IEEEeqnarrayTHEstrutdepth}% +\global\@IEEEeqnarrayusemasterstrutfalse% +\fi} +% usage: \IEEEeqnarraystrutsize{height}{depth}[font size commands] +% If called outside the lines of an IEEEeqnarray, sets the height +% and depth of both the master and local struts. If called inside +% an IEEEeqnarray line, sets the height and depth of the local strut +% only and sets the flag to indicate the use of the local strut +% values. If the height or depth is left blank, 0.7\normalbaselineskip +% and 0.3\normalbaselineskip will be used, respectively. +% The optional argument can be used to evaluate the lengths under +% a different font size and styles. If none is specified, the current +% font is used. +% uses scratch registers \skip0, \skip2, \skip3, \dimen0, \dimen2 +\def\IEEEeqnarraystrutsize#1#2{\relax\@ifnextchar[{\@IEEEeqnarraystrutsize{#1}{#2}}{\@IEEEeqnarraystrutsize{#1}{#2}[\relax]}} +\def\@IEEEeqnarraystrutsize#1#2[#3]{\def\@IEEEeqnarraystrutsizeARG{#1}% +\ifx\@IEEEeqnarraystrutsizeARG\@empty% +{\setbox0=\hbox{#3\relax\global\skip3=0.7\normalbaselineskip}}% +\skip0=\skip3\relax% +\else% arg one present +{\setbox0=\hbox{#3\relax\global\skip3=#1\relax}}% +\skip0=\skip3\relax% +\fi% if null arg +\def\@IEEEeqnarraystrutsizeARG{#2}% +\ifx\@IEEEeqnarraystrutsizeARG\@empty% +{\setbox0=\hbox{#3\relax\global\skip3=0.3\normalbaselineskip}}% +\skip2=\skip3\relax% +\else% arg two present +{\setbox0=\hbox{#3\relax\global\skip3=#2\relax}}% +\skip2=\skip3\relax% +\fi% if null arg +% remove stretchability, just to be safe +\dimen0\skip0\relax% +\dimen2\skip2\relax% +% dimen0 = height, dimen2 = depth +\if@IEEEeqnarrayISinner% inner does not touch master strut size +\edef\@IEEEeqnarrayTHEstrutheight{\the\dimen0}% +\edef\@IEEEeqnarrayTHEstrutdepth{\the\dimen2}% +\@IEEEeqnarrayusemasterstrutfalse% do not use master +\else% outer, have to set master strut too +\edef\@IEEEeqnarrayTHEmasterstrutheight{\the\dimen0}% +\edef\@IEEEeqnarrayTHEmasterstrutdepth{\the\dimen2}% +\edef\@IEEEeqnarrayTHEstrutheight{\the\dimen0}% +\edef\@IEEEeqnarrayTHEstrutdepth{\the\dimen2}% +\@IEEEeqnarrayusemasterstruttrue% use master strut +\fi} + + +% usage: \IEEEeqnarraystrutsizeadd{added height}{added depth}[font size commands] +% If called outside the lines of an IEEEeqnarray, adds the given height +% and depth to both the master and local struts. +% If called inside an IEEEeqnarray line, adds the given height and depth +% to the local strut only and sets the flag to indicate the use +% of the local strut values. +% In both cases, if a height or depth is left blank, 0pt is used instead. +% The optional argument can be used to evaluate the lengths under +% a different font size and styles. If none is specified, the current +% font is used. +% uses scratch registers \skip0, \skip2, \skip3, \dimen0, \dimen2 +\def\IEEEeqnarraystrutsizeadd#1#2{\relax\@ifnextchar[{\@IEEEeqnarraystrutsizeadd{#1}{#2}}{\@IEEEeqnarraystrutsizeadd{#1}{#2}[\relax]}} +\def\@IEEEeqnarraystrutsizeadd#1#2[#3]{\def\@IEEEeqnarraystrutsizearg{#1}% +\ifx\@IEEEeqnarraystrutsizearg\@empty% +\skip0=0pt\relax% +\else% arg one present +{\setbox0=\hbox{#3\relax\global\skip3=#1}}% +\skip0=\skip3\relax% +\fi% if null arg +\def\@IEEEeqnarraystrutsizearg{#2}% +\ifx\@IEEEeqnarraystrutsizearg\@empty% +\skip2=0pt\relax% +\else% arg two present +{\setbox0=\hbox{#3\relax\global\skip3=#2}}% +\skip2=\skip3\relax% +\fi% if null arg +% remove stretchability, just to be safe +\dimen0\skip0\relax% +\dimen2\skip2\relax% +% dimen0 = height, dimen2 = depth +\if@IEEEeqnarrayISinner% inner does not touch master strut size +% get local strut size +\expandafter\skip0=\@IEEEeqnarrayTHEstrutheight\relax% +\expandafter\skip2=\@IEEEeqnarrayTHEstrutdepth\relax% +% add it to the user supplied values +\advance\dimen0 by \skip0\relax% +\advance\dimen2 by \skip2\relax% +% update the local strut size +\edef\@IEEEeqnarrayTHEstrutheight{\the\dimen0}% +\edef\@IEEEeqnarrayTHEstrutdepth{\the\dimen2}% +\@IEEEeqnarrayusemasterstrutfalse% do not use master +\else% outer, have to set master strut too +% get master strut size +\expandafter\skip0=\@IEEEeqnarrayTHEmasterstrutheight\relax% +\expandafter\skip2=\@IEEEeqnarrayTHEmasterstrutdepth\relax% +% add it to the user supplied values +\advance\dimen0 by \skip0\relax% +\advance\dimen2 by \skip2\relax% +% update the local and master strut sizes +\edef\@IEEEeqnarrayTHEmasterstrutheight{\the\dimen0}% +\edef\@IEEEeqnarrayTHEmasterstrutdepth{\the\dimen2}% +\edef\@IEEEeqnarrayTHEstrutheight{\the\dimen0}% +\edef\@IEEEeqnarrayTHEstrutdepth{\the\dimen2}% +\@IEEEeqnarrayusemasterstruttrue% use master strut +\fi} + + +% allow user a way to see the struts +\newif\ifIEEEvisiblestruts +\IEEEvisiblestrutsfalse + +% inserts an invisible strut using the master or local strut values +% uses scratch registers \skip0, \skip2, \dimen0, \dimen2 +\def\@IEEEeqnarrayinsertstrut{\relax% +\if@IEEEeqnarrayusemasterstrut +% get master strut size +\expandafter\skip0=\@IEEEeqnarrayTHEmasterstrutheight\relax% +\expandafter\skip2=\@IEEEeqnarrayTHEmasterstrutdepth\relax% +\else% +% get local strut size +\expandafter\skip0=\@IEEEeqnarrayTHEstrutheight\relax% +\expandafter\skip2=\@IEEEeqnarrayTHEstrutdepth\relax% +\fi% +% remove stretchability, probably not needed +\dimen0\skip0\relax% +\dimen2\skip2\relax% +% dimen0 = height, dimen2 = depth +% allow user to see struts if desired +\ifIEEEvisiblestruts% +\vrule width0.2pt height\dimen0 depth\dimen2\relax% +\else% +\vrule width0pt height\dimen0 depth\dimen2\relax\fi} + + +% creates an invisible strut, useable even outside \IEEEeqnarray +% if \IEEEvisiblestrutstrue, the strut will be visible and 0.2pt wide. +% usage: \IEEEstrut[height][depth][font size commands] +% default is \IEEEstrut[0.7\normalbaselineskip][0.3\normalbaselineskip][\relax] +% blank arguments inherit the default values +% uses \dimen0, \dimen2, \skip0, \skip2 +\def\IEEEstrut{\relax\@ifnextchar[{\@IEEEstrut}{\@IEEEstrut[0.7\normalbaselineskip]}} +\def\@IEEEstrut[#1]{\relax\@ifnextchar[{\@@IEEEstrut[#1]}{\@@IEEEstrut[#1][0.3\normalbaselineskip]}} +\def\@@IEEEstrut[#1][#2]{\relax\@ifnextchar[{\@@@IEEEstrut[#1][#2]}{\@@@IEEEstrut[#1][#2][\relax]}} +\def\@@@IEEEstrut[#1][#2][#3]{\mbox{#3\relax% +\def\@IEEEstrutARG{#1}% +\ifx\@IEEEstrutARG\@empty% +\skip0=0.7\normalbaselineskip\relax% +\else% +\skip0=#1\relax% +\fi% +\def\@IEEEstrutARG{#2}% +\ifx\@IEEEstrutARG\@empty% +\skip2=0.3\normalbaselineskip\relax% +\else% +\skip2=#2\relax% +\fi% +% remove stretchability, probably not needed +\dimen0\skip0\relax% +\dimen2\skip2\relax% +\ifIEEEvisiblestruts% +\vrule width0.2pt height\dimen0 depth\dimen2\relax% +\else% +\vrule width0.0pt height\dimen0 depth\dimen2\relax\fi}} + + +% enables strut mode by setting a default strut size and then zeroing the +% \baselineskip, \lineskip, \lineskiplimit and \jot +\def\IEEEeqnarraystrutmode{\IEEEeqnarraystrutsize{0.7\normalbaselineskip}{0.3\normalbaselineskip}[\relax]% +\baselineskip=0pt\lineskip=0pt\lineskiplimit=0pt\jot=0pt} + + + +\def\IEEEeqnarray{\@IEEEeqnarraystarformfalse\@IEEEeqnarray} +\def\endIEEEeqnarray{\end@IEEEeqnarray} + +\@namedef{IEEEeqnarray*}{\@IEEEeqnarraystarformtrue\@IEEEeqnarray} +\@namedef{endIEEEeqnarray*}{\end@IEEEeqnarray} + + +% \IEEEeqnarray is an enhanced \eqnarray. +% The star form defaults to not putting equation numbers at the end of each row. +% usage: \IEEEeqnarray[decl]{cols} +\def\@IEEEeqnarray{\relax\@ifnextchar[{\@@IEEEeqnarray}{\@@IEEEeqnarray[\relax]}} +\def\@@IEEEeqnarray[#1]#2{% + % default to showing the equation number or not based on whether or not + % the star form was involked + \if@IEEEeqnarraystarform\global\@eqnswfalse + \else% not the star form + \global\@eqnswtrue + \fi% if star form + \@IEEEissubequationfalse% default to no subequations + \@IEEElastlinewassubequationfalse% assume last line is not a sub equation + \@IEEEeqnarrayISinnerfalse% not yet within the lines of the halign + \@IEEEeqnarraystrutsize{0pt}{0pt}[\relax]% turn off struts by default + \@IEEEeqnarrayusemasterstruttrue% use master strut till user asks otherwise + \IEEEvisiblestrutsfalse% diagnostic mode defaults to off + % no extra space unless the user specifically requests it + \lineskip=0pt\relax + \lineskiplimit=0pt\relax + \baselineskip=\normalbaselineskip\relax% + \jot=\IEEEnormaljot\relax% + \mathsurround\z@\relax% no extra spacing around math + \@advanceIEEEeqncolcnttrue% advance the col counter for each col the user uses, + % used in \IEEEeqnarraymulticol and in the preamble build + \stepcounter{equation}% advance equation counter before first line + \setcounter{IEEEsubequation}{0}% no subequation yet + \def\@currentlabel{\p@equation\theequation}% redefine the ref label + \IEEEeqnarraydecl\relax% allow a way for the user to make global overrides + #1\relax% allow user to override defaults + \let\\\@IEEEeqnarraycr% replace newline with one that can put in eqn. numbers + \global\@IEEEeqncolcnt\z@% col. count = 0 for first line + \@IEEEbuildpreamble #2\end\relax% build the preamble and put it into \@IEEEtrantmptoksA + % put in the column for the equation number + \ifnum\@IEEEeqnnumcols>0\relax\@IEEEappendtoksA{&}\fi% col separator for those after the first + \toks0={##}% + % advance the \@IEEEeqncolcnt for the isolation col, this helps with error checking + \@IEEEappendtoksA{\global\advance\@IEEEeqncolcnt by 1\relax}% + % add the isolation column + \@IEEEappendtoksA{\tabskip\z@skip\bgroup\the\toks0\egroup}% + % advance the \@IEEEeqncolcnt for the equation number col, this helps with error checking + \@IEEEappendtoksA{&\global\advance\@IEEEeqncolcnt by 1\relax}% + % add the equation number col to the preamble + \@IEEEappendtoksA{\tabskip\z@skip\hb@xt@\z@\bgroup\hss\the\toks0\egroup}% + % note \@IEEEeqnnumcols does not count the equation col or isolation col + % set the starting tabskip glue as determined by the preamble build + \tabskip=\@IEEEBPstartglue\relax + % begin the display alignment + \@IEEEeqnarrayISinnertrue% commands are now within the lines + $$\everycr{}\halign to\displaywidth\bgroup + % "exspand" the preamble + \span\the\@IEEEtrantmptoksA\cr} + +% enter isolation/strut column (or the next column if the user did not use +% every column), record the strut status, complete the columns, do the strut if needed, +% restore counters to correct values and exit +\def\end@IEEEeqnarray{\@IEEEeqnarrayglobalizestrutstatus&\@@IEEEeqnarraycr\egroup% +\if@IEEElastlinewassubequation\global\advance\c@IEEEsubequation\m@ne\fi% +\global\advance\c@equation\m@ne% +$$\@ignoretrue} + +% need a way to remember if last line is a subequation +\newif\if@IEEElastlinewassubequation% +\@IEEElastlinewassubequationfalse + +% IEEEeqnarray uses a modifed \\ instead of the plain \cr to +% end rows. This allows for things like \\*[vskip amount] +% This "cr" macros are modified versions those for LaTeX2e's eqnarray +% the {\ifnum0=`} braces must be kept away from the last column to avoid +% altering spacing of its math, so we use & to advance to the next column +% as there is an isolation/strut column after the user's columns +\def\@IEEEeqnarraycr{\@IEEEeqnarrayglobalizestrutstatus&% save strut status and advance to next column + {\ifnum0=`}\fi + \@ifstar{% + \global\@eqpen\@M\@IEEEeqnarrayYCR + }{% + \global\@eqpen\interdisplaylinepenalty \@IEEEeqnarrayYCR + }% +} + +\def\@IEEEeqnarrayYCR{\@testopt\@IEEEeqnarrayXCR\z@skip} + +\def\@IEEEeqnarrayXCR[#1]{% + \ifnum0=`{\fi}% + \@@IEEEeqnarraycr + \noalign{\penalty\@eqpen\vskip\jot\vskip #1\relax}}% + +\def\@@IEEEeqnarraycr{\@IEEEtrantmptoksA={}% clear token register + \advance\@IEEEeqncolcnt by -1\relax% adjust col count because of the isolation column + \ifnum\@IEEEeqncolcnt>\@IEEEeqnnumcols\relax + \@IEEEclspkgerror{Too many columns within the IEEEeqnarray\MessageBreak + environment}% + {Use fewer \string &'s or put more columns in the IEEEeqnarry column\MessageBreak + specifications.}\relax% + \else + \loop% add cols if the user did not use them all + \ifnum\@IEEEeqncolcnt<\@IEEEeqnnumcols\relax + \@IEEEappendtoksA{&}% + \advance\@IEEEeqncolcnt by 1\relax% update the col count + \repeat + % this number of &'s will take us the the isolation column + \fi + % execute the &'s + \the\@IEEEtrantmptoksA% + % handle the strut/isolation column + \@IEEEeqnarrayinsertstrut% do the strut if needed + \@IEEEeqnarraystrutreset% reset the strut system for next line or IEEEeqnarray + &% and enter the equation number column + % is this line needs an equation number, display it and advance the + % (sub)equation counters, record what type this line was + \if@eqnsw% + \if@IEEEissubequation\theIEEEsubequationdis\addtocounter{equation}{1}\stepcounter{IEEEsubequation}% + \global\@IEEElastlinewassubequationtrue% + \else% display a standard equation number, initialize the IEEEsubequation counter + \theequationdis\stepcounter{equation}\setcounter{IEEEsubequation}{0}% + \global\@IEEElastlinewassubequationfalse\fi% + \fi% + % reset the eqnsw flag to indicate default preference of the display of equation numbers + \if@IEEEeqnarraystarform\global\@eqnswfalse\else\global\@eqnswtrue\fi + \global\@IEEEissubequationfalse% reset the subequation flag + % reset the number of columns the user actually used + \global\@IEEEeqncolcnt\z@\relax + % the real end of the line + \cr} + + + + + +% \IEEEeqnarraybox is like \IEEEeqnarray except the box form puts everything +% inside a vtop, vbox, or vcenter box depending on the letter in the second +% optional argument (t,b,c). Vbox is the default. Unlike \IEEEeqnarray, +% equation numbers are not displayed and \IEEEeqnarraybox can be nested. +% \IEEEeqnarrayboxm is for math mode (like \array) and does not put the vbox +% within an hbox. +% \IEEEeqnarrayboxt is for text mode (like \tabular) and puts the vbox within +% a \hbox{$ $} construct. +% \IEEEeqnarraybox will auto detect whether to use \IEEEeqnarrayboxm or +% \IEEEeqnarrayboxt depending on the math mode. +% The third optional argument specifies the width this box is to be set to - +% natural width is the default. +% The * forms do not add \jot line spacing +% usage: \IEEEeqnarraybox[decl][pos][width]{cols} +\def\IEEEeqnarrayboxm{\@IEEEeqnarraystarformfalse\@IEEEeqnarrayboxHBOXSWfalse\@IEEEeqnarraybox} +\def\endIEEEeqnarrayboxm{\end@IEEEeqnarraybox} +\@namedef{IEEEeqnarrayboxm*}{\@IEEEeqnarraystarformtrue\@IEEEeqnarrayboxHBOXSWfalse\@IEEEeqnarraybox} +\@namedef{endIEEEeqnarrayboxm*}{\end@IEEEeqnarraybox} + +\def\IEEEeqnarrayboxt{\@IEEEeqnarraystarformfalse\@IEEEeqnarrayboxHBOXSWtrue\@IEEEeqnarraybox} +\def\endIEEEeqnarrayboxt{\end@IEEEeqnarraybox} +\@namedef{IEEEeqnarrayboxt*}{\@IEEEeqnarraystarformtrue\@IEEEeqnarrayboxHBOXSWtrue\@IEEEeqnarraybox} +\@namedef{endIEEEeqnarrayboxt*}{\end@IEEEeqnarraybox} + +\def\IEEEeqnarraybox{\@IEEEeqnarraystarformfalse\ifmmode\@IEEEeqnarrayboxHBOXSWfalse\else\@IEEEeqnarrayboxHBOXSWtrue\fi% +\@IEEEeqnarraybox} +\def\endIEEEeqnarraybox{\end@IEEEeqnarraybox} + +\@namedef{IEEEeqnarraybox*}{\@IEEEeqnarraystarformtrue\ifmmode\@IEEEeqnarrayboxHBOXSWfalse\else\@IEEEeqnarrayboxHBOXSWtrue\fi% +\@IEEEeqnarraybox} +\@namedef{endIEEEeqnarraybox*}{\end@IEEEeqnarraybox} + +% flag to indicate if the \IEEEeqnarraybox needs to put things into an hbox{$ $} +% for \vcenter in non-math mode +\newif\if@IEEEeqnarrayboxHBOXSW% +\@IEEEeqnarrayboxHBOXSWfalse + +\def\@IEEEeqnarraybox{\relax\@ifnextchar[{\@@IEEEeqnarraybox}{\@@IEEEeqnarraybox[\relax]}} +\def\@@IEEEeqnarraybox[#1]{\relax\@ifnextchar[{\@@@IEEEeqnarraybox[#1]}{\@@@IEEEeqnarraybox[#1][b]}} +\def\@@@IEEEeqnarraybox[#1][#2]{\relax\@ifnextchar[{\@@@@IEEEeqnarraybox[#1][#2]}{\@@@@IEEEeqnarraybox[#1][#2][\relax]}} + +% #1 = decl; #2 = t,b,c; #3 = width, #4 = col specs +\def\@@@@IEEEeqnarraybox[#1][#2][#3]#4{\@IEEEeqnarrayISinnerfalse % not yet within the lines of the halign + \@IEEEeqnarraymasterstrutsave% save current master strut values + \@IEEEeqnarraystrutsize{0pt}{0pt}[\relax]% turn off struts by default + \@IEEEeqnarrayusemasterstruttrue% use master strut till user asks otherwise + \IEEEvisiblestrutsfalse% diagnostic mode defaults to off + % no extra space unless the user specifically requests it + \lineskip=0pt\relax% + \lineskiplimit=0pt\relax% + \baselineskip=\normalbaselineskip\relax% + \jot=\IEEEnormaljot\relax% + \mathsurround\z@\relax% no extra spacing around math + % the default end glues are zero for an \IEEEeqnarraybox + \edef\@IEEEeqnarraycolSEPdefaultstart{\@IEEEeqnarraycolSEPzero}% default start glue + \edef\@IEEEeqnarraycolSEPdefaultend{\@IEEEeqnarraycolSEPzero}% default end glue + \edef\@IEEEeqnarraycolSEPdefaultmid{\@IEEEeqnarraycolSEPzero}% default inter-column glue + \@advanceIEEEeqncolcntfalse% do not advance the col counter for each col the user uses, + % used in \IEEEeqnarraymulticol and in the preamble build + \IEEEeqnarrayboxdecl\relax% allow a way for the user to make global overrides + #1\relax% allow user to override defaults + \let\\\@IEEEeqnarrayboxcr% replace newline with one that allows optional spacing + \@IEEEbuildpreamble #4\end\relax% build the preamble and put it into \@IEEEtrantmptoksA + % add an isolation column to the preamble to stop \\'s {} from getting into the last col + \ifnum\@IEEEeqnnumcols>0\relax\@IEEEappendtoksA{&}\fi% col separator for those after the first + \toks0={##}% + % add the isolation column to the preamble + \@IEEEappendtoksA{\tabskip\z@skip\bgroup\the\toks0\egroup}% + % set the starting tabskip glue as determined by the preamble build + \tabskip=\@IEEEBPstartglue\relax + % begin the alignment + \everycr{}% + % use only the very first token to determine the positioning + % this stops some problems when the user uses more than one letter, + % but is probably not worth the effort + % \noindent is used as a delimiter + \def\@IEEEgrabfirstoken##1##2\noindent{\let\@IEEEgrabbedfirstoken=##1}% + \@IEEEgrabfirstoken#2\relax\relax\noindent + % \@IEEEgrabbedfirstoken has the first token, the rest are discarded + % if we need to put things into and hbox and go into math mode, do so now + \if@IEEEeqnarrayboxHBOXSW \leavevmode \hbox \bgroup $\fi% + % use the appropriate vbox type + \if\@IEEEgrabbedfirstoken t\relax\vtop\else\if\@IEEEgrabbedfirstoken c\relax% + \vcenter\else\vbox\fi\fi\bgroup% + \@IEEEeqnarrayISinnertrue% commands are now within the lines + \ifx#3\relax\halign\else\halign to #3\relax\fi% + \bgroup + % "exspand" the preamble + \span\the\@IEEEtrantmptoksA\cr} + +% carry strut status and enter the isolation/strut column, +% exit from math mode if needed, and exit +\def\end@IEEEeqnarraybox{\@IEEEeqnarrayglobalizestrutstatus% carry strut status +&% enter isolation/strut column +\@IEEEeqnarrayinsertstrut% do strut if needed +\@IEEEeqnarraymasterstrutrestore% restore the previous master strut values +% reset the strut system for next IEEEeqnarray +% (sets local strut values back to previous master strut values) +\@IEEEeqnarraystrutreset% +% ensure last line, exit from halign, close vbox +\crcr\egroup\egroup% +% exit from math mode and close hbox if needed +\if@IEEEeqnarrayboxHBOXSW $\egroup\fi} + + + +% IEEEeqnarraybox uses a modifed \\ instead of the plain \cr to +% end rows. This allows for things like \\[vskip amount] +% This "cr" macros are modified versions those for LaTeX2e's eqnarray +% For IEEEeqnarraybox, \\* is the same as \\ +% the {\ifnum0=`} braces must be kept away from the last column to avoid +% altering spacing of its math, so we use & to advance to the isolation/strut column +% carry strut status into isolation/strut column +\def\@IEEEeqnarrayboxcr{\@IEEEeqnarrayglobalizestrutstatus% carry strut status +&% enter isolation/strut column +\@IEEEeqnarrayinsertstrut% do strut if needed +% reset the strut system for next line or IEEEeqnarray +\@IEEEeqnarraystrutreset% +{\ifnum0=`}\fi% +\@ifstar{\@IEEEeqnarrayboxYCR}{\@IEEEeqnarrayboxYCR}} + +% test and setup the optional argument to \\[] +\def\@IEEEeqnarrayboxYCR{\@testopt\@IEEEeqnarrayboxXCR\z@skip} + +% IEEEeqnarraybox does not automatically increase line spacing by \jot +\def\@IEEEeqnarrayboxXCR[#1]{\ifnum0=`{\fi}% +\cr\noalign{\if@IEEEeqnarraystarform\else\vskip\jot\fi\vskip#1\relax}} + + + +% starts the halign preamble build +\def\@IEEEbuildpreamble{\@IEEEtrantmptoksA={}% clear token register +\let\@IEEEBPcurtype=u%current column type is not yet known +\let\@IEEEBPprevtype=s%the previous column type was the start +\let\@IEEEBPnexttype=u%next column type is not yet known +% ensure these are valid +\def\@IEEEBPcurglue={0pt plus 0pt minus 0pt}% +\def\@IEEEBPcurcolname{@IEEEdefault}% name of current column definition +% currently acquired numerically referenced glue +% use a name that is easier to remember +\let\@IEEEBPcurnum=\@IEEEtrantmpcountA% +\@IEEEBPcurnum=0% +% tracks number of columns in the preamble +\@IEEEeqnnumcols=0% +% record the default end glues +\edef\@IEEEBPstartglue{\@IEEEeqnarraycolSEPdefaultstart}% +\edef\@IEEEBPendglue{\@IEEEeqnarraycolSEPdefaultend}% +% now parse the user's column specifications +\@@IEEEbuildpreamble} + + +% parses and builds the halign preamble +\def\@@IEEEbuildpreamble#1#2{\let\@@nextIEEEbuildpreamble=\@@IEEEbuildpreamble% +% use only the very first token to check the end +% \noindent is used as a delimiter as \end can be present here +\def\@IEEEgrabfirstoken##1##2\noindent{\let\@IEEEgrabbedfirstoken=##1}% +\@IEEEgrabfirstoken#1\relax\relax\noindent +\ifx\@IEEEgrabbedfirstoken\end\let\@@nextIEEEbuildpreamble=\@@IEEEfinishpreamble\else% +% identify current and next token type +\@IEEEgetcoltype{#1}{\@IEEEBPcurtype}{1}% current, error on invalid +\@IEEEgetcoltype{#2}{\@IEEEBPnexttype}{0}% next, no error on invalid next +% if curtype is a glue, get the glue def +\if\@IEEEBPcurtype g\@IEEEgetcurglue{#1}{\@IEEEBPcurglue}\fi% +% if curtype is a column, get the column def and set the current column name +\if\@IEEEBPcurtype c\@IEEEgetcurcol{#1}\fi% +% if curtype is a numeral, acquire the user defined glue +\if\@IEEEBPcurtype n\@IEEEprocessNcol{#1}\fi% +% process the acquired glue +\if\@IEEEBPcurtype g\@IEEEprocessGcol\fi% +% process the acquired col +\if\@IEEEBPcurtype c\@IEEEprocessCcol\fi% +% ready prevtype for next col spec. +\let\@IEEEBPprevtype=\@IEEEBPcurtype% +% be sure and put back the future token(s) as a group +\fi\@@nextIEEEbuildpreamble{#2}} + + +% executed just after preamble build is completed +% warn about zero cols, and if prevtype type = u, put in end tabskip glue +\def\@@IEEEfinishpreamble#1{\ifnum\@IEEEeqnnumcols<1\relax +\@IEEEclspkgerror{No column specifiers declared for IEEEeqnarray}% +{At least one column type must be declared for each IEEEeqnarray.}% +\fi%num cols less than 1 +%if last type undefined, set default end tabskip glue +\if\@IEEEBPprevtype u\@IEEEappendtoksA{\tabskip=\@IEEEBPendglue}\fi} + + +% Identify and return the column specifier's type code +\def\@IEEEgetcoltype#1#2#3{% +% use only the very first token to determine the type +% \noindent is used as a delimiter as \end can be present here +\def\@IEEEgrabfirstoken##1##2\noindent{\let\@IEEEgrabbedfirstoken=##1}% +\@IEEEgrabfirstoken#1\relax\relax\noindent +% \@IEEEgrabfirstoken has the first token, the rest are discarded +% n = number +% g = glue (any other char in catagory 12) +% c = letter +% e = \end +% u = undefined +% third argument: 0 = no error message, 1 = error on invalid char +\let#2=u\relax% assume invalid until know otherwise +\ifx\@IEEEgrabbedfirstoken\end\let#2=e\else +\ifcat\@IEEEgrabbedfirstoken\relax\else% screen out control sequences +\if0\@IEEEgrabbedfirstoken\let#2=n\else +\if1\@IEEEgrabbedfirstoken\let#2=n\else +\if2\@IEEEgrabbedfirstoken\let#2=n\else +\if3\@IEEEgrabbedfirstoken\let#2=n\else +\if4\@IEEEgrabbedfirstoken\let#2=n\else +\if5\@IEEEgrabbedfirstoken\let#2=n\else +\if6\@IEEEgrabbedfirstoken\let#2=n\else +\if7\@IEEEgrabbedfirstoken\let#2=n\else +\if8\@IEEEgrabbedfirstoken\let#2=n\else +\if9\@IEEEgrabbedfirstoken\let#2=n\else +\ifcat,\@IEEEgrabbedfirstoken\let#2=g\relax +\else\ifcat a\@IEEEgrabbedfirstoken\let#2=c\relax\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi +\if#2u\relax +\if0\noexpand#3\relax\else\@IEEEclspkgerror{Invalid character in column specifications}% +{Only letters, numerals and certain other symbols are allowed \MessageBreak +as IEEEeqnarray column specifiers.}\fi\fi} + + +% identify the current letter referenced column +% if invalid, use a default column +\def\@IEEEgetcurcol#1{\expandafter\ifx\csname @IEEEeqnarraycolDEF#1\endcsname\@IEEEeqnarraycolisdefined% +\def\@IEEEBPcurcolname{#1}\else% invalid column name +\@IEEEclspkgerror{Invalid column type "#1" in column specifications.\MessageBreak +Using a default centering column instead}% +{You must define IEEEeqnarray column types before use.}% +\def\@IEEEBPcurcolname{@IEEEdefault}\fi} + + +% identify and return the predefined (punctuation) glue value +\def\@IEEEgetcurglue#1#2{% +% ! = \! (neg small) -0.16667em (-3/18 em) +% , = \, (small) 0.16667em ( 3/18 em) +% : = \: (med) 0.22222em ( 4/18 em) +% ; = \; (large) 0.27778em ( 5/18 em) +% ' = \quad 1em +% " = \qquad 2em +% . = 0.5\arraycolsep +% / = \arraycolsep +% ? = 2\arraycolsep +% * = 1fil +% + = \@IEEEeqnarraycolSEPcenter +% - = \@IEEEeqnarraycolSEPzero +% Note that all em values are referenced to the math font (textfont2) fontdimen6 +% value for 1em. +% +% use only the very first token to determine the type +% this prevents errant tokens from getting in the main text +% \noindent is used as a delimiter here +\def\@IEEEgrabfirstoken##1##2\noindent{\let\@IEEEgrabbedfirstoken=##1}% +\@IEEEgrabfirstoken#1\relax\relax\noindent +% get the math font 1em value +% LaTeX2e's NFSS2 does not preload the fonts, but \IEEEeqnarray needs +% to gain access to the math (\textfont2) font's spacing parameters. +% So we create a bogus box here that uses the math font to ensure +% that \textfont2 is loaded and ready. If this is not done, +% the \textfont2 stuff here may not work. +% Thanks to Bernd Raichle for his 1997 post on this topic. +{\setbox0=\hbox{$\displaystyle\relax$}}% +% fontdimen6 has the width of 1em (a quad). +\@IEEEtrantmpdimenA=\fontdimen6\textfont2\relax% +% identify the glue value based on the first token +% we discard anything after the first +\if!\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=-0.16667\@IEEEtrantmpdimenA\edef#2{\the\@IEEEtrantmpdimenA}\else +\if,\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=0.16667\@IEEEtrantmpdimenA\edef#2{\the\@IEEEtrantmpdimenA}\else +\if:\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=0.22222\@IEEEtrantmpdimenA\edef#2{\the\@IEEEtrantmpdimenA}\else +\if;\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=0.27778\@IEEEtrantmpdimenA\edef#2{\the\@IEEEtrantmpdimenA}\else +\if'\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=1\@IEEEtrantmpdimenA\edef#2{\the\@IEEEtrantmpdimenA}\else +\if"\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=2\@IEEEtrantmpdimenA\edef#2{\the\@IEEEtrantmpdimenA}\else +\if.\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=0.5\arraycolsep\edef#2{\the\@IEEEtrantmpdimenA}\else +\if/\@IEEEgrabbedfirstoken\edef#2{\the\arraycolsep}\else +\if?\@IEEEgrabbedfirstoken\@IEEEtrantmpdimenA=2\arraycolsep\edef#2{\the\@IEEEtrantmpdimenA}\else +\if *\@IEEEgrabbedfirstoken\edef#2{0pt plus 1fil minus 0pt}\else +\if+\@IEEEgrabbedfirstoken\edef#2{\@IEEEeqnarraycolSEPcenter}\else +\if-\@IEEEgrabbedfirstoken\edef#2{\@IEEEeqnarraycolSEPzero}\else +\edef#2{\@IEEEeqnarraycolSEPzero}% +\@IEEEclspkgerror{Invalid predefined inter-column glue type "#1" in\MessageBreak +column specifications. Using a default value of\MessageBreak +0pt instead}% +{Only !,:;'"./?*+ and - are valid predefined glue types in the\MessageBreak +IEEEeqnarray column specifications.}\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi} + + + +% process a numerical digit from the column specification +% and look up the corresponding user defined glue value +% can transform current type from n to g or a as the user defined glue is acquired +\def\@IEEEprocessNcol#1{\if\@IEEEBPprevtype g% +\@IEEEclspkgerror{Back-to-back inter-column glue specifiers in column\MessageBreak +specifications. Ignoring consecutive glue specifiers\MessageBreak +after the first}% +{You cannot have two or more glue types next to each other\MessageBreak +in the IEEEeqnarray column specifications.}% +\let\@IEEEBPcurtype=a% abort this glue, future digits will be discarded +\@IEEEBPcurnum=0\relax% +\else% if we previously aborted a glue +\if\@IEEEBPprevtype a\@IEEEBPcurnum=0\let\@IEEEBPcurtype=a%maintain digit abortion +\else%acquire this number +% save the previous type before the numerical digits started +\if\@IEEEBPprevtype n\else\let\@IEEEBPprevsavedtype=\@IEEEBPprevtype\fi% +\multiply\@IEEEBPcurnum by 10\relax% +\advance\@IEEEBPcurnum by #1\relax% add in number, \relax is needed to stop TeX's number scan +\if\@IEEEBPnexttype n\else%close acquisition +\expandafter\ifx\csname @IEEEeqnarraycolSEPDEF\expandafter\romannumeral\number\@IEEEBPcurnum\endcsname\@IEEEeqnarraycolisdefined% +\edef\@IEEEBPcurglue{\csname @IEEEeqnarraycolSEP\expandafter\romannumeral\number\@IEEEBPcurnum\endcsname}% +\else%user glue not defined +\@IEEEclspkgerror{Invalid user defined inter-column glue type "\number\@IEEEBPcurnum" in\MessageBreak +column specifications. Using a default value of\MessageBreak +0pt instead}% +{You must define all IEEEeqnarray numerical inter-column glue types via\MessageBreak +\string\IEEEeqnarraydefcolsep \space before they are used in column specifications.}% +\edef\@IEEEBPcurglue{\@IEEEeqnarraycolSEPzero}% +\fi% glue defined or not +\let\@IEEEBPcurtype=g% change the type to reflect the acquired glue +\let\@IEEEBPprevtype=\@IEEEBPprevsavedtype% restore the prev type before this number glue +\@IEEEBPcurnum=0\relax%ready for next acquisition +\fi%close acquisition, get glue +\fi%discard or acquire number +\fi%prevtype glue or not +} + + +% process an acquired glue +% add any acquired column/glue pair to the preamble +\def\@IEEEprocessGcol{\if\@IEEEBPprevtype a\let\@IEEEBPcurtype=a%maintain previous glue abortions +\else +% if this is the start glue, save it, but do nothing else +% as this is not used in the preamble, but before +\if\@IEEEBPprevtype s\edef\@IEEEBPstartglue{\@IEEEBPcurglue}% +\else%not the start glue +\if\@IEEEBPprevtype g%ignore if back to back glues +\@IEEEclspkgerror{Back-to-back inter-column glue specifiers in column\MessageBreak +specifications. Ignoring consecutive glue specifiers\MessageBreak +after the first}% +{You cannot have two or more glue types next to each other\MessageBreak +in the IEEEeqnarray column specifications.}% +\let\@IEEEBPcurtype=a% abort this glue +\else% not a back to back glue +\if\@IEEEBPprevtype c\relax% if the previoustype was a col, add column/glue pair to preamble +\ifnum\@IEEEeqnnumcols>0\relax\@IEEEappendtoksA{&}\fi +\toks0={##}% +% make preamble advance col counter if this environment needs this +\if@advanceIEEEeqncolcnt\@IEEEappendtoksA{\global\advance\@IEEEeqncolcnt by 1\relax}\fi +% insert the column defintion into the preamble, being careful not to expand +% the column definition +\@IEEEappendtoksA{\tabskip=\@IEEEBPcurglue}% +\@IEEEappendNOEXPANDtoksA{\begingroup\csname @IEEEeqnarraycolPRE}% +\@IEEEappendtoksA{\@IEEEBPcurcolname}% +\@IEEEappendNOEXPANDtoksA{\endcsname}% +\@IEEEappendtoksA{\the\toks0}% +\@IEEEappendNOEXPANDtoksA{\relax\relax\relax\relax\relax% +\relax\relax\relax\relax\relax\csname @IEEEeqnarraycolPOST}% +\@IEEEappendtoksA{\@IEEEBPcurcolname}% +\@IEEEappendNOEXPANDtoksA{\endcsname\relax\relax\relax\relax\relax% +\relax\relax\relax\relax\relax\endgroup}% +\advance\@IEEEeqnnumcols by 1\relax%one more column in the preamble +\else% error: non-start glue with no pending column +\@IEEEclspkgerror{Inter-column glue specifier without a prior column\MessageBreak +type in the column specifications. Ignoring this glue\MessageBreak +specifier}% +{Except for the first and last positions, glue can be placed only\MessageBreak +between column types.}% +\let\@IEEEBPcurtype=a% abort this glue +\fi% previous was a column +\fi% back-to-back glues +\fi% is start column glue +\fi% prev type not a +} + + +% process an acquired letter referenced column and, if necessary, add it to the preamble +\def\@IEEEprocessCcol{\if\@IEEEBPnexttype g\else +\if\@IEEEBPnexttype n\else +% we have a column followed by something other than a glue (or numeral glue) +% so we must add this column to the preamble now +\ifnum\@IEEEeqnnumcols>0\relax\@IEEEappendtoksA{&}\fi%col separator for those after the first +\if\@IEEEBPnexttype e\@IEEEappendtoksA{\tabskip=\@IEEEBPendglue\relax}\else%put in end glue +\@IEEEappendtoksA{\tabskip=\@IEEEeqnarraycolSEPdefaultmid\relax}\fi% or default mid glue +\toks0={##}% +% make preamble advance col counter if this environment needs this +\if@advanceIEEEeqncolcnt\@IEEEappendtoksA{\global\advance\@IEEEeqncolcnt by 1\relax}\fi +% insert the column definition into the preamble, being careful not to expand +% the column definition +\@IEEEappendNOEXPANDtoksA{\begingroup\csname @IEEEeqnarraycolPRE}% +\@IEEEappendtoksA{\@IEEEBPcurcolname}% +\@IEEEappendNOEXPANDtoksA{\endcsname}% +\@IEEEappendtoksA{\the\toks0}% +\@IEEEappendNOEXPANDtoksA{\relax\relax\relax\relax\relax% +\relax\relax\relax\relax\relax\csname @IEEEeqnarraycolPOST}% +\@IEEEappendtoksA{\@IEEEBPcurcolname}% +\@IEEEappendNOEXPANDtoksA{\endcsname\relax\relax\relax\relax\relax% +\relax\relax\relax\relax\relax\endgroup}% +\advance\@IEEEeqnnumcols by 1\relax%one more column in the preamble +\fi%next type not numeral +\fi%next type not glue +} + + +%% +%% END OF IEEEeqnarry DEFINITIONS +%% + + + + +% \IEEEPARstart +% Definition for the big two line drop cap letter at the beginning of the +% first paragraph of journal papers. The first argument is the first letter +% of the first word, the second argument is the remaining letters of the +% first word which will be rendered in upper case. +% In V1.6 this has been completely rewritten to: +% +% 1. no longer have problems when the user begins an environment +% within the paragraph that uses \IEEEPARstart. +% 2. auto-detect and use the current font family +% 3. revise handling of the space at the end of the first word so that +% interword glue will now work as normal. +% 4. produce correctly aligned edges for the (two) indented lines. +% +% We generalize things via control macros - playing with these is fun too. +% +% For IEEEtrantools, we do not use a "@" in the names as these are user +% alterable controls. +% +% V1.7 added more control macros to make it easy for IEEEtrantools.sty users +% to change the font style. +% +% the number of lines that are indented to clear it +% may need to increase if using decenders +\providecommand{\IEEEPARstartDROPLINES}{2} +% minimum number of lines left on a page to allow a \@IEEEPARstart +% Does not take into consideration rubber shrink, so it tends to +% be overly cautious +\providecommand{\IEEEPARstartMINPAGELINES}{2} +% V1.7 the height of the drop cap is adjusted to match the height of this text +% in the current font (when \IEEEPARstart is called). +\providecommand{\IEEEPARstartHEIGHTTEXT}{T} +% the depth the letter is lowered below the baseline +% the height (and size) of the letter is determined by the sum +% of this value and the height of the \IEEEPARstartHEIGHTTEXT in the current +% font. It is a good idea to set this value in terms of the baselineskip +% so that it can respond to changes therein. +\providecommand{\IEEEPARstartDROPDEPTH}{1.1\baselineskip} +% V1.7 the font the drop cap will be rendered in, +% can take zero or one argument. +\providecommand{\IEEEPARstartFONTSTYLE}{\bfseries} +% V1.7 any additional, non-font related commands needed to modify +% the drop cap letter, can take zero or one argument. +\providecommand{\IEEEPARstartCAPSTYLE}{\MakeUppercase} +% V1.7 the font that will be used to render the rest of the word, +% can take zero or one argument. +\providecommand{\IEEEPARstartWORDFONTSTYLE}{\relax} +% V1.7 any additional, non-font related commands needed to modify +% the rest of the word, can take zero or one argument. +\providecommand{\IEEEPARstartWORDCAPSTYLE}{\MakeUppercase} +% This is the horizontal separation distance from the drop letter to the main text. +% Lengths that depend on the font (e.g., ex, em, etc.) will be referenced +% to the font that is active when \IEEEPARstart is called. +\providecommand{\IEEEPARstartSEP}{0.15em} +% V1.7 horizontal offset applied to the left of the drop cap. +\providecommand{\IEEEPARstartHOFFSET}{0em} +% V1.7 Italic correction command applied at the end of the drop cap. +\providecommand{\IEEEPARstartITLCORRECT}{\/} + +% width of the letter output, set globally. Can be used in \IEEEPARstartSEP +% or \IEEEPARstartHOFFSET, but not the height lengths. +\newdimen\IEEEPARstartletwidth +\IEEEPARstartletwidth 0pt\relax + +% definition of \IEEEPARstart +% THIS IS A CONTROLLED SPACING AREA, DO NOT ALLOW SPACES WITHIN THESE LINES +% +% The token \@IEEEPARstartfont will be globally defined after the first use +% of \IEEEPARstart and will be a font command which creates the big letter +% The first argument is the first letter of the first word and the second +% argument is the rest of the first word(s). +\def\IEEEPARstart#1#2{\par{% +% if this page does not have enough space, break it and lets start +% on a new one +\@IEEEtranneedspace{\IEEEPARstartMINPAGELINES\baselineskip}{\relax}% +% V1.7 move this up here in case user uses \textbf for \IEEEPARstartFONTSTYLE +% which uses command \leavevmode which causes an unwanted \indent to be issued +\noindent +% calculate the desired height of the big letter +% it extends from the top of \IEEEPARstartHEIGHTTEXT in the current font +% down to \IEEEPARstartDROPDEPTH below the current baseline +\settoheight{\@IEEEtrantmpdimenA}{\IEEEPARstartHEIGHTTEXT}% +\addtolength{\@IEEEtrantmpdimenA}{\IEEEPARstartDROPDEPTH}% +% extract the name of the current font in bold +% and place it in \@IEEEPARstartFONTNAME +\def\@IEEEPARstartGETFIRSTWORD##1 ##2\relax{##1}% +{\IEEEPARstartFONTSTYLE{\selectfont\edef\@IEEEPARstartFONTNAMESPACE{\fontname\font\space}% +\xdef\@IEEEPARstartFONTNAME{\expandafter\@IEEEPARstartGETFIRSTWORD\@IEEEPARstartFONTNAMESPACE\relax}}}% +% define a font based on this name with a point size equal to the desired +% height of the drop letter +\font\@IEEEPARstartsubfont\@IEEEPARstartFONTNAME\space at \@IEEEtrantmpdimenA\relax% +% save this value as a counter (integer) value (sp points) +\@IEEEtrantmpcountA=\@IEEEtrantmpdimenA% +% now get the height of the actual letter produced by this font size +\settoheight{\@IEEEtrantmpdimenB}{\@IEEEPARstartsubfont\IEEEPARstartCAPSTYLE{#1}}% +% If something bogus happens like the first argument is empty or the +% current font is strange, do not allow a zero height. +\ifdim\@IEEEtrantmpdimenB=0pt\relax% +\typeout{** WARNING: IEEEPARstart drop letter has zero height! (line \the\inputlineno)}% +\typeout{ Forcing the drop letter font size to 10pt.}% +\@IEEEtrantmpdimenB=10pt% +\fi% +% and store it as a counter +\@IEEEtrantmpcountB=\@IEEEtrantmpdimenB% +% Since a font size doesn't exactly correspond to the height of the capital +% letters in that font, the actual height of the letter, \@IEEEtrantmpcountB, +% will be less than that desired, \@IEEEtrantmpcountA +% we need to raise the font size, \@IEEEtrantmpdimenA +% by \@IEEEtrantmpcountA / \@IEEEtrantmpcountB +% But, TeX doesn't have floating point division, so we have to use integer +% division. Hence the use of the counters. +% We need to reduce the denominator so that the loss of the remainder will +% have minimal affect on the accuracy of the result +\divide\@IEEEtrantmpcountB by 200% +\divide\@IEEEtrantmpcountA by \@IEEEtrantmpcountB% +% Then reequalize things when we use TeX's ability to multiply by +% floating point values +\@IEEEtrantmpdimenB=0.005\@IEEEtrantmpdimenA% +\multiply\@IEEEtrantmpdimenB by \@IEEEtrantmpcountA% +% \@IEEEPARstartfont is globaly set to the calculated font of the big letter +% We need to carry this out of the local calculation area to to create the +% big letter. +\global\font\@IEEEPARstartfont\@IEEEPARstartFONTNAME\space at \@IEEEtrantmpdimenB% +% Now set \@IEEEtrantmpdimenA to the width of the big letter +% We need to carry this out of the local calculation area to set the +% hanging indent +\settowidth{\global\@IEEEtrantmpdimenA}{\@IEEEPARstartfont +\IEEEPARstartCAPSTYLE{#1\IEEEPARstartITLCORRECT}}}% +% end of the isolated calculation environment +\global\IEEEPARstartletwidth\@IEEEtrantmpdimenA\relax% +% add in the extra clearance we want +\advance\@IEEEtrantmpdimenA by \IEEEPARstartSEP\relax% +% add in the optional offset +\advance\@IEEEtrantmpdimenA by \IEEEPARstartHOFFSET\relax% +% V1.7 don't allow negative offsets to produce negative hanging indents +\@IEEEtrantmpdimenB\@IEEEtrantmpdimenA +\ifnum\@IEEEtrantmpdimenB < 0 \@IEEEtrantmpdimenB 0pt\fi +% \@IEEEtrantmpdimenA has the width of the big letter plus the +% separation space and \@IEEEPARstartfont is the font we need to use +% Now, we make the letter and issue the hanging indent command +% The letter is placed in a box of zero width and height so that other +% text won't be displaced by it. +\hangindent\@IEEEtrantmpdimenB\hangafter=-\IEEEPARstartDROPLINES% +\makebox[0pt][l]{\hspace{-\@IEEEtrantmpdimenA}% +\raisebox{-\IEEEPARstartDROPDEPTH}[0pt][0pt]{\hspace{\IEEEPARstartHOFFSET}% +\@IEEEPARstartfont\IEEEPARstartCAPSTYLE{#1\IEEEPARstartITLCORRECT}% +\hspace{\IEEEPARstartSEP}}}% +{\IEEEPARstartWORDFONTSTYLE{\IEEEPARstartWORDCAPSTYLE{\selectfont#2}}}} + + + + + + +% determines if the space remaining on a given page is equal to or greater +% than the specified space of argument one +% if not, execute argument two (only if the remaining space is greater than zero) +% and issue a \newpage +% +% example: \@IEEEtranneedspace{2in}{\vfill} +% +% Does not take into consideration rubber shrinkage, so it tends to +% be overly cautious +% Based on an example posted by Donald Arseneau +% Note this macro uses \@IEEEtrantmpdimenB internally for calculations, +% so DO NOT PASS \@IEEEtrantmpdimenB to this routine +% if you need a dimen register, import with \@IEEEtrantmpdimenA instead +\def\@IEEEtranneedspace#1#2{\penalty-100\begingroup%shield temp variable +\@IEEEtrantmpdimenB\pagegoal\advance\@IEEEtrantmpdimenB-\pagetotal% space left +\ifdim #1>\@IEEEtrantmpdimenB\relax% not enough space left +\ifdim\@IEEEtrantmpdimenB>\z@\relax #2\fi% +\newpage% +\fi\endgroup} + + + + + + +% Provide support for the control entries of IEEEtran.bst V1.00 and later. +% V1.7 optional argument allows for a different aux file to be specified in +% order to handle multiple bibliographies. For example, with multibib.sty: +% \newcites{sec}{Secondary Literature} +% \bstctlcite[@auxoutsec]{BSTcontrolhak} +% V1.7 I see no need for \providecommand here. +\def\bstctlcite{\@ifnextchar[{\@bstctlcite}{\@bstctlcite[@auxout]}} +\def\@bstctlcite[#1]#2{\@bsphack + \@for\@citeb:=#2\do{% + \edef\@citeb{\expandafter\@firstofone\@citeb}% + \if@filesw\immediate\write\csname #1\endcsname{\string\citation{\@citeb}}\fi}% + \@esphack} + + + +% need a backslash character for typeout output +{\catcode`\|=0 \catcode`\\=12 +|xdef|@IEEEbackslash{\}} + + +% hook to allow easy disabling of all legacy warnings +\def\@IEEElegacywarn#1#2{\typeout{** ATTENTION: \@IEEEbackslash #1 is depreciated (line \the\inputlineno). +Use \@IEEEbackslash #2 instead.}} + +% provide for legacy commands +\def\PARstart{\@IEEElegacywarn{PARstart}{IEEEPARstart}\IEEEPARstart} + +% provide for legacy IED commands/lengths when possible +\let\labelindent\IEEElabelindent +\def\calcleftmargin{\@IEEElegacywarn{calcleftmargin}{IEEEcalcleftmargin}\IEEEcalcleftmargin} +\def\setlabelwidth{\@IEEElegacywarn{setlabelwidth}{IEEEsetlabelwidth}\IEEEsetlabelwidth} +\def\usemathlabelsep{\@IEEElegacywarn{usemathlabelsep}{IEEEusemathlabelsep}\IEEEusemathlabelsep} +\def\iedlabeljustifyc{\@IEEElegacywarn{iedlabeljustifyc}{IEEEiedlabeljustifyc}\IEEEiedlabeljustifyc} +\def\iedlabeljustifyl{\@IEEElegacywarn{iedlabeljustifyl}{IEEEiedlabeljustifyl}\IEEEiedlabeljustifyl} +\def\iedlabeljustifyr{\@IEEElegacywarn{iedlabeljustifyr}{IEEEiedlabeljustifyr}\IEEEiedlabeljustifyr} + + +\endinput +%%%%%%%%%%%%%%%%%%%%%%%%%% End of IEEEtrantools.sty %%%%%%%%%%%%%%%%%%%%%% +% That's all folks! + diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d3f3b600e4e1a0b70fa95f7440893c4e4ef14a28 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,22 @@ +PDFS := codes-best-practices.pdf + +all: $(PDFS) + @ echo REMAINING TODO ITEMS : `grep TODO codes-best-practices.tex | wc -l` + +figs:: + $(MAKE) -C figs + +%.pdf: %.eps + epstopdf $< + +%.pdf: %.tex + pdflatex $< + pdflatex $< + pdflatex $< + +codes-best-practices.pdf: codes-best-practices.tex + pdflatex $< + pdflatex $< + +clean:: + rm -f $(PDFS) *.dvi *.aux *.bbl *.log *.bak *.toc *.blg *.lof *.ps diff --git a/doc/Makefile.subdir b/doc/Makefile.subdir new file mode 100644 index 0000000000000000000000000000000000000000..f082bb2f5b3a11328155c78ef23155370c80ea21 --- /dev/null +++ b/doc/Makefile.subdir @@ -0,0 +1,25 @@ +docs_general = doc/BUILD_STEPS doc/GETTING_STARTED doc/RELEASE_NOTES + +docs_best_practices = \ + doc/acmsmall.cls \ + doc/algorithm.sty \ + doc/algorithmic.sty \ + doc/codes-best-practices.tex \ + doc/Makefile + +docs_examples = \ + doc/example/example.c \ + doc/example/example.conf \ + doc/example/Makefile \ + doc/example_heterogeneous/example.c \ + doc/example_heterogeneous/example.conf \ + doc/example_heterogeneous/example_torus.conf \ + doc/example_heterogeneous/Makefile \ + doc/example_heterogeneous/README + +docs_workload = \ + doc/workload/example.kernel.txt \ + doc/workload/meta.txt + +EXTRA_DIST += $(docs_general) $(docs_best_practices) $(docs_examples) \ + $(docs_workload) diff --git a/doc/RELEASE_NOTES b/doc/RELEASE_NOTES new file mode 100644 index 0000000000000000000000000000000000000000..7353a3964c0b8d1f7345ef91890139d285572b66 --- /dev/null +++ b/doc/RELEASE_NOTES @@ -0,0 +1,49 @@ +0.4.0 + +general: +========== +significant source reorganization / refactoring +refactor some private headers out of the public eye +dead code removal + +documentation: +========== +improved example_heterogeneous example program +added configuration to example_heterogeneous showing two torus networks +reorganized files to prevent name collisions on OSX. Top-level docs other than + copyright now in doc directory +additions to best practice document + +configurator: +========== +more stable file format for configurator output +ignore unrelated parameters passed into filter_configs +handle empty cfields in configurator + +workloads: +========== +combined network and IO workload APIs into a single one +adding dumpi workload support in codes-workload-dump utility +workload dump utility option cleanup +renamed "bgp" workload generator to "iolang", significant cleanups +put network workload ops in workload dump util +removing one of the dumpi libraries from the build. It was generating some unwanted dumpi files. +network workload API more fleshed out + +utilities: +========== +configuration bug fixes for larger LP type counts +resource LP annotation mapping hooks +local storage model API switch to use annotations +better configuration error handling +hedge against precision loss in codes_local_latency (see codes.h) +use a different RNG than default for codes_local_latency +- prevents addition/removal of codes_local_latency calls from poisoning RNG + stream of calling model +added simple GVT-aware stack with garbage collection (see rc-stack.h) + + +0.3.0 + +Initial "official" release. Against previous repository revisions, this release +includes more complete documentation. diff --git a/doc/acmsmall.cls b/doc/acmsmall.cls new file mode 100644 index 0000000000000000000000000000000000000000..81552793e66295d9a53321004aa21d3e2185bc8f --- /dev/null +++ b/doc/acmsmall.cls @@ -0,0 +1,3256 @@ +%% acmsmall.cls - version 1.1 +%% Aptara Inc., dated 15 July 2010 +%% (c) 2010 Association for Computing Machinery (ACM) +%% For small trim journals +%% +%% Based on ESUB2ACM.CLS V1.2 - November 10th. 1999 +%% +%% If you face any problem while working with this class file or have any feedback/suggestion, +%% please contact ACM Support helpline at: "acmtexsupport@aptaracorp.com". +%% Users can also go through the FAQs available on the journal's submission webpage. +%% +%% Version 1.1 (History) +%% --------------------- +%% 1) All citation formats are also redefined after +%% checking the loading condition of natbib.sty +%% 2) Added an option called 'prodmode', which uses New Century School Book +%% and Helvetica as base and second font respectively after +%% feedback from Joanne (Dated 28/06/2010) to simulate print output. +%% 3) Changed running head style (Joanne 02/07/2010) +%% 4) Added three new transactions (Jono 14/07/2010) +%% +%% Steps to compile: latex, bibtex, latex latex +%% +%% \CharacterTable +%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +%% Digits \0\1\2\3\4\5\6\7\8\9 +%% Exclamation \! Double quote \" Hash (number) \# +%% Dollar \$ Percent \% Ampersand \& +%% Acute accent \' Left paren \( Right paren \) +%% Asterisk \* Plus \+ Comma \, +%% Minus \- Point \. Solidus \/ +%% Colon \: Semicolon \; Less than \< +%% Equals \= Greater than \> Question mark \? +%% Commercial at \@ Left bracket \[ Backslash \\ +%% Right bracket \] Circumflex \^ Underscore \_ +%% Grave accent \` Left brace \{ Vertical bar \| +%% Right brace \} Tilde \~} +%% +%% Bibliographic cite forms needed: +%% +%% \cite{key} +%% which produces citations with author list and year. +%% eg. [Brown 1978; Jarke, et al. 1985] +%% \citeA{key} +%% which produces citations with only the author list. +%% eg. [Brown; Jarke, et al.] +%% \citeN{key} +%% which produces citations with the author list and year, but +%% can be used as nouns in a sentence; no brackets appear around +%% the author names, but only around the year. +%% eg. Shneiderman [1978] states that...... +%% \citeN should only be used for a single citation. +%% \citeNN{refkey1,refkey2} for author [ref1year; ref2year] +%% \citeyear{key} +%% which produces the year information only, within brackets. +%% +%% Abbreviated author lists use the ``et al.'' construct. +%% +%% The above are examples of required ACM bibliographic cite formats needed. +%% ******************* +%% Here is the complete list of cite forms from the chicago bibliographic style +%% +%% \cite{key} +%% which produces citations with abbreviated author list and year. +%% \citeNP{key} +%% which produces citations with abbreviated author list and year. +%% \citeA{key} +%% which produces only the abbreviated author list. +%% \citeANP{key} +%% which produces only the abbreviated author list. +%% \citeN{key} +%% which produces the abbreviated author list and year, with only the +%% year in parentheses. Use with only one citation. +%% \citeyear{key} +%% which produces the year information only, within parentheses. +%% \citeyearNP{key} +%% which produces the year information only. +%% +%% Abbreviated author lists use the ``et al.'' construct. +%% +%% `NP' means `no parentheses' +%% +\NeedsTeXFormat{LaTeX2e} +\ProvidesClass{acmsmall}[2010/07/15, fonts included on 28 June 2010] + +\def\fileversion{v1.1} +\def\filedate{July 15, 2010} + +% Metadata Information +\def\@acmVolume{V} %the volume +\def\@acmNumber{N} %the number +\def\@acmArticle{A} %article number +\def\@articleSeq{1} %article Sequence +\def\@acmPrice{10.00} %article price +\def\@acmYear{YYYY} %the last two digits of the year, +\def\@acmMonth{1} %the month +\def\@journalName{ACM Journal Name} %the name of the ACM journal +\def\@journalNameShort{ACM} %the acronym of the ACM journal +\def\@journalCode{jn} %the code of the ACM journal +\def\@permissionCodeOne{0000-0000} %the permission code of the ACM journal +\def\@doi{0000000.0000000} + +\if@compatibility\else +\DeclareOption{letterpaper} + {\setlength\paperheight {11in}% + \setlength\paperwidth {8.5in}% + \setlength\voffset {-38.2pt}% + \setlength\hoffset {-8.25pt}% + \def\special@paper{8.5in,11in} + % Needed to set PDF page size + \special{papersize=8.5in,11in}} +\DeclareOption{landscape} + {\setlength\@tempdima {\paperheight}% + \setlength\paperheight {\paperwidth}% + \setlength\paperwidth {\@tempdima}} +\fi + +\DeclareOption{oneside}{\@twosidefalse \@mparswitchfalse} +\DeclareOption{twoside}{\@twosidetrue \@mparswitchtrue} + +\DeclareOption{final}{\setlength\overfullrule{0pt}} + +\DeclareOption{10pt}{\def\@ptsize{0}} %needed for amssymbols.sty +\DeclareOption{11pt}{\ClassError{acmsmall}{11pt style not supported} + {ACM transactions/journals documents can be set in 10pt only}} +\DeclareOption{12pt}{\ClassError{acmtrans}{12pt style not supported} + {ACM transactions/journals documents can be set in 10pt only}} + +\newif\ifprod@mode\prod@modefalse +\DeclareOption{prodmode}{\global\prod@modetrue +\typeout{ACM, Production Font style: 2010/06/28 by Aptara}} + +\newif\if@acmjacm +\newif\if@acmtissec +\newif\if@acmtocl +\newif\if@acmtocs +\newif\if@acmtochi +\newif\if@acmtodaes +\newif\if@acmtods +\newif\if@acmtois +\newif\if@acmtomacs +\newif\if@acmtoms +\newif\if@acmtoplas +\newif\if@acmtosem +\newif\if@acmtoit +\newif\if@acmtecs +\newif\if@acmtalip +\newif\if@acmjeric +\newif\if@acmtaco +\newif\if@acmjea +\newif\if@acmtslp +\newif\if@acmcie +\newif\if@acmtos +\newif\if@acmcsur +\newif\if@acmjetc +\newif\if@acmtosn +\newif\if@acmtalg +\newif\if@acmtaas +\newif\if@acmtweb +\newif\if@acmtkdd +\newif\if@acmtrets +\newif\if@acmtmis +\newif\if@acmtiis +\newif\if@acmtist + +% Journal Options +\DeclareOption{acmjacm}{ + \typeout{} + \typeout{Using ACM, JACM's option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmtrue + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{Journal of the ACM} + \def\@journalNameShort{J. ACM} + \def\@journalCode{jacm} + \def\@permissionCodeOne{0004-5411} +} + +\DeclareOption{acmtissec}{ + \typeout{} + \typeout{Using ACM, TISSEC's option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissectrue + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Information and System Security} + \def\@journalNameShort{ACM Trans. Info. Syst. Sec.} + \def\@journalCode{tissec} + \def\@permissionCodeOne{1094-9224} +} + +\DeclareOption{acmtocl}{ + \typeout{} + \typeout{Using ACM, TOCL's option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtocltrue + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Computational Logic} + \def\@journalNameShort{ACM Trans. Comput. Logic} + \def\@journalCode{tocl} + \def\@permissionCodeOne{1529-3785} +} + +\DeclareOption{acmtocs}{ + \typeout{} + \typeout{Using ACM, TOCS's option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocstrue + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Computer Systems} + \def\@journalNameShort{ACM Trans. Comput. Syst.} + \def\@journalCode{tocs} + \def\@permissionCodeOne{0734-2071} +} + +\DeclareOption{acmtochi}{ + \typeout{} + \typeout{Using ACM, TOCHI's option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochitrue + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Computer-Human Interaction} + \def\@journalNameShort{ACM Trans. Comput.-Hum. Interact.} + \def\@journalCode{tochi} + \def\@permissionCodeOne{1073-0516} +} + +\DeclareOption{acmtodaes}{ + \typeout{} + \typeout{Using ACM, TODAES option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaestrue + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Design Automation of Electronic Systems} + \def\@journalNameShort{ACM Trans. Des. Autom. Electron. Syst.} + \def\@journalCode{todaes} + \def\@permissionCodeOne{1084-4309} +} + +\DeclareOption{acmtods}{ + \typeout{} + \typeout{Using ACM, TODS's option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodstrue + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Database Systems} + \def\@journalNameShort{ACM Trans. Datab. Syst.} + \def\@journalCode{tods} + \def\@permissionCodeOne{0362-5915} +} + +\DeclareOption{acmtois}{ + \typeout{} + \typeout{Using ACM, TOIS's option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoistrue + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Information Systems} + \def\@journalNameShort{ACM Trans. Inf. Syst.} + \def\@journalCode{tois} + \def\@permissionCodeOne{1046-8188} +} + +\DeclareOption{acmtomacs}{ + \typeout{} + \typeout{Using ACM, TOMACS's option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacstrue + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Modeling and Computer Simulation} + \def\@journalNameShort{ACM Trans. Model. Comput. Simul.} + \def\@journalCode{tomacs} + \def\@permissionCodeOne{1049-3301} +} + +\DeclareOption{acmtoms}{ + \typeout{} + \typeout{Using ACM, TOMS's option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomstrue + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Mathematical Software} + \def\@journalNameShort{ACM Trans. Math. Softw.} + \def\@journalCode{toms} + \def\@permissionCodeOne{0098-3500} +} + +\DeclareOption{acmtoplas}{ + \typeout{} + \typeout{Using ACM, TOPLAS option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplastrue + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Programming Languages and Systems} + \def\@journalNameShort{ACM Trans. Program. Lang. Syst.} + \def\@journalCode{toplas} + \def\@permissionCodeOne{0164-0925} +} + +\DeclareOption{acmtosem}{ + \typeout{} + \typeout{Using ACM, TOSEM option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemtrue + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Software Engineering and Methodology} + \def\@journalNameShort{ACM Trans. Softw. Eng. Methodol.} + \def\@journalCode{tosem} + \def\@permissionCodeOne{1049-331X} +} + +\DeclareOption{acmtoit}{ + \typeout{} + \typeout{Using ACM, TOIT option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoittrue + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Internet Technology} + \def\@journalNameShort{ACM Trans. Internet Technol.} + \def\@journalCode{toit} + \def\@permissionCodeOne{1533-5399} +} + +\DeclareOption{acmtecs}{ + \typeout{} + \typeout{Using ACM, TECS option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecstrue + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Embedded Computing Systems} + \def\@journalNameShort{ACM Trans. Embedd. Comput. Syst.} + \def\@journalCode{tecs} + \def\@permissionCodeOne{1539-9087} +} + +\DeclareOption{acmtalip}{ + \typeout{} + \typeout{Using ACM, TALIP option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtaliptrue + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Trans. on Asian Language Information Processing} + \def\@journalNameShort{ACM Trans. Asian Language Inform. Process.} + \def\@journalCode{talip} + \def\@permissionCodeOne{1530-0226} +} + +\DeclareOption{acmjeric}{ + \typeout{} + \typeout{Using ACM, JERIC option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjerictrue + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Journal of Educational Resources in Computing} + \def\@journalNameShort{ACM J. Edu. Resources in Comput.} + \def\@journalCode{jeric} + \def\@permissionCodeOne{1073-0516} +} + +\DeclareOption{acmtaco}{ + \typeout{} + \typeout{Using ACM, TACO option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacotrue + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Architecture and Code Optimization} + \def\@journalNameShort{ACM Trans. Architec. Code Optim.} + \def\@journalCode{taco} + \def\@permissionCodeOne{1544-3566} +} + +\DeclareOption{acmjea}{ + \typeout{} + \typeout{Using ACM, JEA option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeatrue + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Journal of Experimental Algorithmics} + \def\@journalNameShort{ACM J. Exp. Algor.} + \def\@journalCode{jea} + \def\@permissionCodeOne{1084-6654} +} + +\DeclareOption{acmtslp}{ + \typeout{} + \typeout{Using ACM, TSLP option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslptrue + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Speech and Language Processing} + \def\@journalNameShort{ACM Trans. Speech Lang. Process.} + \def\@journalCode{tslp} + \def\@permissionCodeOne{1550-4875} +} + +\DeclareOption{acmcie}{ + \typeout{} + \typeout{Using ACM, CIE option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmcietrue + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Computers in Entertainment} + \def\@journalNameShort{ACM Comput. Entertain.} + \def\@journalCode{cie} + \def\@permissionCodeOne{1544-3574} +} + +\DeclareOption{acmtos}{ + \typeout{} + \typeout{Using ACM, TOS option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtostrue + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Storage} + \def\@journalNameShort{ACM Trans. Storage} + \def\@journalCode{tos} + \def\@permissionCodeOne{1553-3077} +} + +\DeclareOption{acmcsur}{ + \typeout{} + \typeout{Using ACM, CSUR option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurtrue + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Computing Surveys} + \def\@journalNameShort{ACM Comput. Surv.} + \def\@journalCode{csur} + \def\@permissionCodeOne{0360-0300} +} + +\DeclareOption{acmjetc}{ + \typeout{} + \typeout{Using ACM, JETC option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetctrue + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Journal on Emerging Technologies in Computing Systems} + \def\@journalNameShort{ACM J. Emerg. Technol. Comput. Syst.} + \def\@journalCode{jetc} + \def\@permissionCodeOne{1550-4832} +} + +\DeclareOption{acmtosn}{ + \typeout{} + \typeout{Using ACM, TOSN option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosntrue + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Sensor Networks} + \def\@journalNameShort{ACM Trans. Sensor Netw.} + \def\@journalCode{tosn} + \def\@permissionCodeOne{1550-4859} +} + +\DeclareOption{acmtalg}{ + \typeout{} + \typeout{Using ACM, TALG option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgtrue + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Algorithms} + \def\@journalNameShort{ACM Trans. Algor.} + \def\@journalCode{talg} + \def\@permissionCodeOne{1549-6325} +} + +\DeclareOption{acmtaas}{ + \typeout{} + \typeout{Using ACM, TAAS option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaastrue + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Autonomous and Adaptive Systems} + \def\@journalNameShort{ACM Trans. Autonom. Adapt. Syst.} + \def\@journalCode{taas} + \def\@permissionCodeOne{1556-4665} +} + +\DeclareOption{acmtweb}{ + \typeout{} + \typeout{Using ACM, TWEB option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebtrue + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on the Web} + \def\@journalNameShort{ACM Trans. Web} + \def\@journalCode{tweb} + \def\@permissionCodeOne{1559-1131} +} + +\DeclareOption{acmtkdd}{ + \typeout{} + \typeout{Using ACM, TKDD option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddtrue + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Knowledge Discovery from Data} + \def\@journalNameShort{ACM Trans. Knowl. Discov. Data.} + \def\@journalCode{tkdd} + \def\@permissionCodeOne{1556-4681} +} + +\DeclareOption{acmtrets}{ + \typeout{} + \typeout{Using ACM, TRETS option: 2010/05/04 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretstrue + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Reconfigurable Technology and Systems} + \def\@journalNameShort{ACM Trans. Reconfig. Technol. Syst.} + \def\@journalCode{trets} + \def\@permissionCodeOne{1936-7406} +} + +\DeclareOption{acmtmis}{ + \typeout{} + \typeout{Using ACM, TMIS option: 2010/07/14 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmistrue + \global\@acmtiisfalse + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Management Information Systems} + \def\@journalNameShort{ACM Trans. Manag. Inform. Syst.} + \def\@journalCode{tmis} + \def\@permissionCodeOne{0000-0001} +} + +\DeclareOption{acmtiis}{ + \typeout{} + \typeout{Using ACM, TIIS option: 2010/07/14 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiistrue + \global\@acmtistfalse + \def\@journalName{ACM Transactions on Transactions on Interactive Intelligent Systems} + \def\@journalNameShort{ACM Trans. Interact. Intell. Syst.} + \def\@journalCode{tiis} + \def\@permissionCodeOne{0000-0002} +} + +\DeclareOption{acmtist}{ + \typeout{} + \typeout{Using ACM, TIST option: 2010/07/14 by Aptara} + \typeout{} + \global\@acmjacmfalse + \global\@acmtissecfalse + \global\@acmtoclfalse + \global\@acmtocsfalse + \global\@acmtochifalse + \global\@acmtodaesfalse + \global\@acmtodsfalse + \global\@acmtoisfalse + \global\@acmtomacsfalse + \global\@acmtomsfalse + \global\@acmtoplasfalse + \global\@acmtosemfalse + \global\@acmtoitfalse + \global\@acmtecsfalse + \global\@acmtalipfalse + \global\@acmjericfalse + \global\@acmtacofalse + \global\@acmjeafalse + \global\@acmtslpfalse + \global\@acmciefalse + \global\@acmtosfalse + \global\@acmcsurfalse + \global\@acmjetcfalse + \global\@acmtosnfalse + \global\@acmtalgfalse + \global\@acmtaasfalse + \global\@acmtwebfalse + \global\@acmtkddfalse + \global\@acmtretsfalse + \global\@acmtmisfalse + \global\@acmtiisfalse + \global\@acmtisttrue + \def\@journalName{ACM Transactions on Intelligent Systems and Technology} + \def\@journalNameShort{ACM Trans. Intell. Syst. Technol.} + \def\@journalCode{tist} + \def\@permissionCodeOne{0000-0003} +} + +\ExecuteOptions{twoside,final,10pt,letterpaper} +\ProcessOptions + +% Including fonts for Production Mode +\ifprod@mode +% New Century Schoolbook as base font +\renewcommand\rmdefault{pnc} +% Helvetica as second font +\renewcommand\sfdefault{phv} +\fi + +% Packages required +\RequirePackage{latexsym} +\RequirePackage{color} +\usepackage{graphicx} + + +\typeout{Document Class `acmsmall' Electronic Submissions +\fileversion\space <\filedate> (ACM).} + +\def\acmVolume#1{\def\@acmVolume{#1}} +\def\acmNumber#1{\def\@acmNumber{#1}} +\def\acmArticle#1{\def\@acmArticle{#1}} +\def\articleSeq#1{\def\@articleSeq{#1}} +\def\acmPrice#1{\def\@acmPrice{#1}} +\def\acmYear#1{\def\@acmYear{#1}} +\def\acmMonth#1{\def\@acmMonth{#1}} +\def\doi#1{\def\@doi{#1}} + + +%To transform the month number in its name in English +\newcommand{\monthWord}[1]{\ifcase#1\or + January\or February\or March\or April\or May\or June\or + July\or August\or September\or October\or November\or December\else Month\fi} + +\newcommand{\monthInf}[1]{\ifcase#1\or + 01\or 02\or 03\or 04\or 05\or 06\or + 07\or 08\or 09\or 10\or 11\or 12\else 00\fi} + +% First and Last page +\newcount\@firstpg +\newcount\@lastpg +\def\lastpage#1{\global\advance\@lastpg#1\relax} +\AtEndDocument{\ifelec@app\else\immediate\write\@mainaux{\string\lastpage{\the\c@page}}\fi} + +\newdimen\trimheight +\newdimen\trimwidth +\newdimen\normaltextheight +\newdimen\tempdimen +\newbox\tempbox +\newbox\tbbox +\newdimen\tabledim + +% Extra symbol +\DeclareSymbolFont{newlargesymbols}{OMX}{cmex}{m}{n} +\DeclareMathSymbol{\bigsqcup}{\mathop}{newlargesymbols}{"46} + +% Bold Math +\def\boldmath{\mathversion{bold}} +\def\bm#1{\mathchoice + {\mbox{\boldmath$\displaystyle#1$}}% + {\mbox{\boldmath$#1$}}% + {\mbox{\boldmath$\scriptstyle#1$}}% + {\mbox{\boldmath$\scriptscriptstyle#1$}}} + +% Font information +\lineskip1\p@ +\normallineskip1\p@ +\def\baselinestretch{1} +\def\@ptsize{0} % needed for amssymbols.sty + +\@maxdepth\maxdepth +\DeclareOldFontCommand{\rm}{\normalfont\rmfamily}{\mathrm} +\DeclareOldFontCommand{\sf}{\normalfont\sffamily}{\mathsf} +\DeclareOldFontCommand{\tt}{\normalfont\ttfamily}{\mathtt} +\DeclareOldFontCommand{\bf}{\normalfont\bfseries}{\mathbf} +\DeclareOldFontCommand{\it}{\normalfont\itshape}{\mathit} +\DeclareOldFontCommand{\sl}{\normalfont\slshape}{\@nomath\sl} +\DeclareOldFontCommand{\sc}{\normalfont\scshape}{\@nomath\sc} +\newcommand{\pcal}{\@fontswitch{\relax}{\mathcal}} +\newcommand{\mit}{\protect\pmit} +\newcommand{\pmit}{\@fontswitch{\relax}{\mathnormal}} +\def\cal{\mathcal} + +\renewcommand{\@ptsize}{} +\renewcommand{\normalsize}{% + \@setfontsize\normalsize\@xpt{11\p@}% + \abovedisplayskip .5\baselineskip \@plus2\p@ \@minus\p@ + \belowdisplayskip \abovedisplayskip + \abovedisplayshortskip 6\p@ \@minus 3\p@ + \belowdisplayshortskip 6\p@ \@minus 3\p@ + \let\@listi\@listI +} +\newcommand{\small}{% + \@setfontsize\small\@ixpt{10\p@}% + \abovedisplayskip 5\p@ \@plus 2\p@ \@minus \p@ + \belowdisplayskip \abovedisplayskip + \abovedisplayshortskip 5\p@ \@minus 2\p@ + \belowdisplayshortskip 5\p@ \@minus 2\p@ + \def\@listi{% + \leftmargin\leftmargini + \topsep 5\p@ \@plus 2\p@ \@minus .2\p@ + \parsep \z@ \@plus .7\p@ + \itemsep 1.6\p@ \@plus .8\p@}% +}% + +\newcommand{\footnotesize}{% + \@setfontsize\footnotesize\@viiipt{9\p@}% + \abovedisplayskip 4\p@ \@plus \p@ + \belowdisplayskip \abovedisplayskip + \abovedisplayshortskip 4\p@ \@minus \p@ + \belowdisplayshortskip 4\p@ \@minus \p@ + \def\@listi{% + \leftmargin\leftmargini + \topsep 4\p@ \@plus \p@ + \parsep \z@ \@plus .5\p@ + \itemsep \p@ \@plus .7\p@} +}% +\normalsize + +\newcommand\scriptsize{\@setfontsize\scriptsize\@viipt\@viiipt} +\newcommand\tiny{\@setfontsize\tiny\@vpt\@vipt} +\newcommand\large{\@setfontsize\large\@xiipt{14}} +\newcommand\Large{\@setfontsize\Large\@xivpt{18}} +\newcommand\LARGE{\@setfontsize\LARGE\@xviipt{22}} +\newcommand\huge{\@setfontsize\huge\@xxpt{25}} +\newcommand\Huge{\@setfontsize\Huge\@xxvpt{30}} + +\def\rhfont{\fontfamily{\sfdefault}\fontsize{9}{10}\selectfont} +\def\rfootfont{\fontsize{7}{8}\selectfont} +\def\foliofont{\fontfamily{\sfdefault}\fontsize{9}{10}\selectfont} + +\def\sectionfont{\fontfamily{\sfdefault}\fontsize{9}{11}\selectfont\bfseries\raggedright} +\def\refsectionfont{\fontfamily{\sfdefault}\fontsize{9}{11}\selectfont\bfseries} +\def\subsectionfont{\fontfamily{\sfdefault}\fontsize{9}{11}\selectfont\bfseries\raggedright} +\def\subsubsectionfont{\fontfamily{\sfdefault}\fontsize{9}{11}\selectfont\itshape\raggedright} +\def\paragraphfont{\fontsize{10}{11}\selectfont\itshape} + +\def\figcaptionfont{\fontsize{8}{9}\selectfont}% +\def\figcaptionnumfont{\fontfamily{\sfdefault}\fontsize{8}{9}\selectfont}% +\def\subcaptionfont{\fontsize{8}{10}\selectfont}% +\def\subcaption#1{{\centering\subcaptionfont#1\par}} + +\def\tablefont{\fontsize{8}{9}\selectfont}% +\def\intexttablefont{\fontsize{8}{9}\selectfont\centering}% +\def\tablecaptionfont{\fontfamily{\sfdefault}\fontsize{8}{9}\selectfont}% +\def\tablenumfont{\fontfamily{\sfdefault}\fontsize{8}{9}\selectfont}% +\def\tabnotefont{\fontsize{8}{9}\selectfont} +\def\ackfont{\fontsize{8}{10}\selectfont} + +\setlength\trimheight {10in} +\setlength\trimwidth {6.75in} + +\textheight 48pc +\advance\textheight-7.3pt +\setlength\normaltextheight{\textheight} + +\textwidth 33pc +\oddsidemargin .625in +\evensidemargin\trimwidth +\advance\evensidemargin-\oddsidemargin +\advance\evensidemargin-\textwidth + +\marginparwidth .5in +\marginparsep .125in +\topmargin 36pt +\headheight 6.5\p@ +\topskip6.2pt +\headsep 17.5pt +\parindent10\p@ +\newdimen\normalparindent +\normalparindent\parindent + +\newlength{\footheight}% +\footheight 10\p@ +\footskip 28\p@ + +\columnsep 12\p@ +\columnseprule 0\p@ + +\footnotesep 7\p@ +\skip\footins 15\p@ plus 4\p@ minus 3\p@ +\floatsep 1\baselineskip plus 2\p@ minus 2\p@ +\textfloatsep \floatsep +\intextsep 1pc plus 1pc + +\newlength{\@maxsep}% +\@maxsep 1pc + +\dblfloatsep 1\baselineskip plus 2\p@ minus 2\p@ +\dbltextfloatsep 20\p@ plus 2\p@ minus 4\p@ + +\newlength{\@dblmaxsep}% +\@dblmaxsep 20\p@ + +\@fptop 0\p@ plus 1fil +\@fpsep 1pc plus 2fil +\@fpbot 0\p@ plus 1fil +\@dblfptop 0\p@ plus 1fil +\@dblfpsep 8\p@ plus 2fil +\@dblfpbot 0\p@ plus 1fil + +\marginparpush 6\p@ + +\parskip0\p@ +\partopsep 0\p@ +\@lowpenalty 51 +\@medpenalty 151 +\@highpenalty 301 + +\@beginparpenalty -\@lowpenalty +\@endparpenalty -\@lowpenalty +\@itempenalty -\@lowpenalty + +\setcounter{topnumber}{3} +\def\topfraction{.99} +\setcounter{bottomnumber}{1} +\def\bottomfraction{.5} +\setcounter{totalnumber}{3} +\def\textfraction{.01} +\def\floatpagefraction{.85} +\setcounter{dbltopnumber}{2} +\def\dbltopfraction{.7} +\def\dblfloatpagefraction{.5} + +% Copyright Information +\def\cpyright#1{\gdef\@cpyright{#1}} +\cpyright{ACM\ \@permissionCodeOne/\@acmYear/\monthInf{\@acmMonth}-ART\@acmArticle} + +% Calculating total pages +\newcount\@totalpg +\def\acmPages#1{\def\@acmPages{#1}} +\acmPages{\@totalpg\@lastpg\global\advance\@totalpg-\@firstpg\global\advance\@totalpg\@ne\ifnum\the\@totalpg<\z@0\else\the\@totalpg\fi\ pages} + +% Reference Format +\gdef\formatline{\@journalNameShort\ \@acmVolume, \@acmNumber, Article~\@acmArticle\ (\monthWord{\@acmMonth}\ \@acmYear), \@acmPages.\\ +DOI $=$ 10.1145/\@doi\ http://doi.acm.org/10.1145/\@doi} +\gdef\copyrightline{\copyright\ \@acmYear\ \@cpyright\ \$\@acmPrice} +\gdef\doiline{DOI\ 10.1145/\@doi\ \ http://doi.acm.org/10.1145/\@doi} + +% Page Style +\mark{{}{}} + +\def\ps@headings{% + \let\@mkboth\@gobbletwo + \def\@oddhead{{\rhfont\rightmark}\hfill{\foliofont \@acmArticle:\thepage}}% + \def\@evenhead{{\foliofont \@acmArticle:\thepage}\hfill{\rhfont\leftmark}}% + \def\@evenfoot{\null\hfill{\rfootfont\@runningfoot}} + \def\@oddfoot{{\rfootfont\@runningfoot} \hfill\null}% + \let\partmark\@gobble + \let\sectionmark\@gobble + \let\subsectionmark\@gobble +} + +\def\ps@appheadings{% + \let\@mkboth\@gobbletwo + \def\@oddhead{{\rhfont\rightmark}\hfill{\foliofont \thepage}}% + \def\@evenhead{{\foliofont \thepage}\hfill{\rhfont\leftmark}}% + \def\@evenfoot{\null\hfill{\rfootfont\@runningfoot}} + \def\@oddfoot{{\rfootfont\@runningfoot} \hfill\null}% + \let\partmark\@gobble + \let\sectionmark\@gobble + \let\subsectionmark\@gobble +} + +\def\@runningfoot{} +\def\runningfoot#1{\gdef\@runningfoot{#1}} + +\if@acmtodaes + \def\pubphrase{Pub. date} +\else +\if@acmtosem + \def\pubphrase{Pub. date} +\else +\if@acmjetc + \def\pubphrase{Pub. date} +\else +\if@acmtiis + \def\pubphrase{Pub. date} +\else + \def\pubphrase{Publication date} +\fi\fi\fi\fi + +\runningfoot{\@journalName, Vol.~\@acmVolume, No.~\@acmNumber, Article~\@acmArticle,\ \pubphrase:\ \monthWord{\@acmMonth}\ \@acmYear.} + +\def\@firstfoot{} +\gdef\firstfoot{\@journalName, Vol.~\@acmVolume,\ No.~\@acmNumber,\ Article\ \@acmArticle,\ \pubphrase:\ \monthWord{\@acmMonth}\ \@acmYear.} + +\def\ps@titlepage{% + \let\@mkboth\@gobbletwo + \let\@oddhead\@empty + \def\@oddfoot{\null\hfill\fontsize{7}{8}\selectfont\firstfoot} + \let\@evenhead\@empty + \def\@evenfoot{\fontsize{7}{8}\selectfont\firstfoot\hfill\null}% +} + +\def\titlepage{% + \@restonecolfalse + \if@twocolumn + \@restonecoltrue + \onecolumn + \else + \newpage + \fi + \thispagestyle{empty}% + \c@page\z@ +} + +\def\endtitlepage{% + \if@restonecol + \twocolumn + \else + \newpage + \fi +} + +% Author and Affiliation +\def\author#1{\gdef\@author{#1}}% +\def\and{{\upshape and }} +\def\affil#1{\gdef\@affil{#1}\ifx\@affil\@empty\else{\reset@font\affilfont\unskip,\ #1\vphantom{gy}\endgraf}\fi}\affil{} + +\def\titlefont{\fontfamily{\sfdefault}\fontsize{12}{12}\selectfont\bfseries} +\def\authorfont{\fontfamily{\sfdefault}\fontsize{10}{11}\rightskip0pt plus1fill\selectfont} +\def\affilfont{\fontfamily{\rmdefault}\fontsize{8}{11}\rightskip0pt plus1fill\selectfont} +\def\abstractfont{\fontsize{8}{10}\selectfont} + +% Article Title page +\def\maketitle{% + \newpage + \thispagestyle{titlepage}% + \global\@topnum\z@ + \begingroup + \lineskip \z@ + \null + \vskip -15.4\p@\relax + \parindent\z@ + \begingroup + \raggedright + \hyphenpenalty\@M + {\titlefont\@title\par} + \global\@firstpg\the\c@page + \endgroup + \vskip 12\p@ + \begingroup + + {\addtolength{\baselineskip}{2\p@}% + {\authorfont\@author\par} + \vskip7pt + \ifx \@sponsors\@empty + \else + \hbox{\vrule height .2\p@ width \textwidth} + \@sponsors \par + \fi + } +\endgroup + \par\vskip 22\p@\box\@abstract + \par% + \ifx\@categories\@empty + \else + \abstractfont + \vskip 4\p@\relax + \def\and{\unskip{\rm;} }% + \noindent Categories and Subject Descriptors: \@categories\par + \fi + \ifx\@terms\@empty\else + \abstractfont + \vskip 4\p@ + \noindent General Terms: \ignorespaces + \@terms + \par + \fi + \ifx\@keywords\@empty\else + \abstractfont + \vskip 4\p@ + \noindent Additional Key Words and Phrases: \ignorespaces + \@keywords + \par + \fi + \ifx\@acmformat\@empty\else + \abstractfont + \vskip 4\p@ + \noindent {\bf ACM Reference Format:}\\ + \@acmformat\vskip 0.5\p@ + \par + \fi + \par + \endgroup + \let\maketitle\relax + \global\let\@sponsors\@empty + \global\let\@categories\@empty + \global\let\@terms\@empty + \global\let\@keywords\@empty + } + +% Sponsor +\def\sponsor#1{\@ifnextchar + [{\@sponsor{#1}}{\@xsponsor{#1}}} +\def\@sponsor#1[#2]{\edef\@tempa{\ifx \@sponsors\@empty + \else ; \fi}{\def\protect{\noexpand\protect + \noexpand}\def\and{\noexpand\and}\xdef\@sponsors{\@sponsors\@tempa #1 }}} +\def\@xsponsor#1{\edef\@tempa{\ifx \@sponsors\@empty \else ; +\fi}{\def\protect{\noexpand\protect\noexpand}\def\and{\noexpand + \and}\xdef\@sponsors{\@sponsors\@tempa #1}}} +\def\@sponsors{} + +% Abstract +\newbox\@abstract +\def\abstract{ +\global\setbox\@abstract=\vbox\bgroup\everypar{}% +\abstractfont\noindent\ignorespaces} +\def\endabstract{\egroup} + +% Terms +\def\terms#1{\gdef\@terms{#1}} +\let\@terms\@empty + +% Keywords +\def\keywords#1{\gdef\@keywords{#1}} +\let\@keywords\@empty + +% Reference Format +\def\acmformat#1{\gdef\@acmformat{#1 \formatline\vphantom{y}}} +\let\@acmformat\@empty + +% Category +\def\category#1#2#3{% + \@ifnextchar [{\@category{#1}{#2}{#3}}{\@category{#1}{#2}{#3}[]}} +\def\@category#1#2#3[#4]{% + \edef\@tempa{\ifx \@categories\@empty \else ; \fi}% + \begingroup + \def\protect{\noexpand\protect\noexpand}% + \let\and\relax + \xdef\@categories{% + \@categories + \@tempa + #1 [{\bf #2}]% + \if!#4!% + \if!#3!\else : #3\fi + \else + :\space + \if!#3!\else #3\kern\z@---\hskip\z@\fi + {\it #4}% + \fi + }% + \endgroup +} + +% Permission Information +\newbox\@permissionbox +\newenvironment{permission}{% + \footnotesize + \global\setbox\@permissionbox\vbox\bgroup\par\addvspace{3.1pt}\noindent\ignorespaces + }{% + \par\egroup} +% +\let\@categories\@empty +\def\bottomstuff{% + \global\@topnum\z@ + \global\@botroom \textheight + \@float{figure}[b] + \footnotesize + \parindent\z@ + \null + \vskip -\textfloatsep + \vskip 6\p@ plus2pt minus2pt + \hrule \@height .5\p@ \@width \textwidth + \vskip 6\p@ %7.5 + \ignorespaces +} +\def\endbottomstuff{\par% +Permission to make digital or hard copies of part or all of this work +for personal or classroom use is +granted without fee provided that copies are not made or distributed for profit or commercial +advantage and that copies show this notice on the first page or initial screen of a display +along with the full citation. Copyrights for components of this work owned by others than ACM +must be honored. Abstracting with credit is permitted. To copy otherwise, to republish, +to post on servers, to redistribute to lists, or to use any component of this work in other +works requires prior specific permission and\hspace*{.5pt}/or a fee. +Permissions may be requested from Publications Dept., ACM, Inc., 2 Penn Plaza, Suite 701, +New York, NY 10121-0701 USA, fax $+$1 (212) 869-0481, +or permissions@acm.org.\par\box\@permissionbox +\copyrightline\par +\doiline +\vskip-13pt +\strut +\end@float +} + +% Heads +\newcounter{part} +\newcounter{section} +\newcounter{subsection}[section] +\newcounter{subsubsection}[subsection] +\newcounter{paragraph}[subsubsection] +\def\thepart{\Roman{part}} +\def\thesection{\arabic{section}} +\def\thesubsection{\thesection.\arabic{subsection}} +\def\thesubsubsection{\thesubsection.\arabic{subsubsection}} +\def\theparagraph{\thesubsubsection.\arabic{paragraph}} + +% for checking Uppercase heads +\newif\if@uchead\@ucheadfalse + +\setcounter{secnumdepth}{3} +\def\part{\@startsection{part}{9}{\z@}% + {-10\p@ \@plus -4\p@ \@minus -2\p@}% + {4\p@}% + {\normalsize\itshape\@ucheadtrue}} +\def\section{\@startsection{section}{1}{\z@}% + {-.75\baselineskip \@plus -2\p@ \@minus -.2\p@}% + {.25\baselineskip}% + {\sectionfont\@ucheadtrue}} +\def\refsection{\@startsection{section}{1}{\z@}% + {-1\baselineskip \@plus -2\p@ \@minus -.2\p@}% + {.5\baselineskip}% + {\refsectionfont\@ucheadtrue}} +\def\subsection{\@startsection{subsection}{2}{\z@}% + {-.75\baselineskip \@plus -2\p@ \@minus -.2\p@}% + {.25\baselineskip}% + {\subsectionfont}} +\def\subsubsection{\@startsection{subsubsection}{3}{10pt}% + {-.5\baselineskip \@plus -2\p@ \@minus -.2\p@}% + {-3.5\p@}{\subsubsectionfont}} +\def\paragraph{\@startsection{paragraph}{4}{\parindent}% + {-.5\baselineskip \@plus -2\p@ \@minus -.2\p@}% + {-3.5\p@}% + {\paragraphfont}} + +\def\@seccntformat#1{\csname the#1\endcsname.\hskip .4em} +\let\@period=. +\def\@sect#1#2#3#4#5#6[#7]#8{% + \ifnum #2>\c@secnumdepth + \let\@svsec\@empty + \else + \refstepcounter{#1}% + \edef\@svsec{\begingroup\csname the#1\endcsname\endgroup\relax .\hskip .4em}% + \protected@edef\@svsec{\@seccntformat{#1}\relax}% + \fi + \@tempskipa #5\relax + \ifdim \@tempskipa>\z@ + \begingroup + #6{% + \@hangfrom{\hskip #3\relax\@svsec}% + \interlinepenalty \@M \if@uchead\MakeUppercase{#8}\else#8\fi\@@par}% + \endgroup + \csname #1mark\endcsname{#7}% + \addcontentsline{toc}{#1}{% + \ifnum #2>\c@secnumdepth \else + \protect\numberline{\csname the#1\endcsname}% + \fi + #7}% + \else + \def\@svsechd{% + #6{\hskip #3\relax + \@svsec #8}% + \csname #1mark\endcsname{#7}% + \addcontentsline{toc}{#1}{% + \ifnum #2>\c@secnumdepth \else + \protect\numberline{\csname the#1\endcsname}% + \fi + #7}}% + \fi + \@xsect{#5}} +\def\@xsect#1{% + \@tempskipa #1\relax + \ifdim \@tempskipa>\z@ + \par + \nobreak + \vskip \@tempskipa + \@afterheading + \else + \global\@nobreakfalse + \global\@noskipsectrue + \everypar{% + \if@noskipsec + \global\@noskipsecfalse + \clubpenalty\@M + \hskip -\parindent + \begingroup + \@svsechd + \@period + \endgroup + \unskip + \@tempskipa #1\relax + \hskip -\@tempskipa + \else + \clubpenalty \@clubpenalty + \everypar{}% + \fi + }% + \fi + \ignorespaces +} + +% Lists +\def\@trivlist{% + \@topsepadd\topsep + \if@noskipsec + \global\let\@period\@empty + \leavevmode + \global\let\@period.% + \fi + \ifvmode + \advance\@topsepadd\partopsep + \else + \unskip + \par + \fi + \if@inlabel + \@noparitemtrue + \@noparlisttrue + \else + \@noparlistfalse + \@topsep\@topsepadd + \fi + \advance\@topsep \parskip + \leftskip\z@skip + \rightskip\@rightskip + \parfillskip\@flushglue + \@setpar{\if@newlist\else{\@@par}\fi} + \global\@newlisttrue + \@outerparskip\parskip +} +\labelsep 5\p@ + +\settowidth{\leftmargini}{9.} +\addtolength\leftmargini\labelsep + +\settowidth{\leftmarginii}{(b)} +\addtolength\leftmarginii\labelsep + +\leftmarginiii \leftmarginii +\leftmarginiv \leftmarginii +\leftmarginv \leftmarginii +\leftmarginvi \leftmarginii +\leftmargin \leftmargini + +\labelwidth\leftmargini +\advance\labelwidth-\labelsep +\def\@listI{% + \leftmargin\leftmargini + \parsep \z@ + \topsep .5\baselineskip \@plus 2\p@% + \itemsep\z@% +} + +\let\@listi\@listI + +\@listi +\def\@listii{% + \leftmargin\leftmarginii + \labelwidth\leftmarginii + \advance\labelwidth-\labelsep + \topsep \z@ + \parsep \z@ + \itemsep \parsep +} +\def\@listiii{% + \leftmargin\leftmarginiii + \labelwidth\leftmarginiii + \advance\labelwidth-\labelsep + \topsep \z@ \@plus \p@ + \parsep \z@ + \itemsep \parsep +} +\def\@listiv{% + \leftmargin\leftmarginiv + \labelwidth\leftmarginiv + \advance\labelwidth-\labelsep +} +\def\@listv{% + \leftmargin\leftmarginv + \labelwidth\leftmarginv + \advance\labelwidth-\labelsep +} +\def\@listvi{% + \leftmargin\leftmarginvi + \labelwidth\leftmarginvi + \advance\labelwidth-\labelsep +} +\newdimen\enumdim +\def\enummax#1{% + \setbox\tempbox\hbox{#1\hskip\labelsep}% + \enumdim\wd\tempbox + \expandafter\global\csname leftmargin\romannumeral\the\@enumdepth\endcsname + \enumdim} + +\enummax{1.} +\def\enumerate{\@ifnextchar[{\@enumerate}{\@enumerate[\csname label\@enumctr\endcsname]}}%% +\def\@enumerate[#1]{\par\abovedisplayskip .25\baselineskip \@plus2\p@ + \belowdisplayskip .25\baselineskip \@plus2\p@ + \ifnum \@enumdepth >3 \@toodeep\else + \advance\@enumdepth\@ne + \edef\@enumctr{enum\romannumeral\the\@enumdepth}% + \setcounter{\@enumctr}{1}\enummax{#1}% + \list + {\csname label\@enumctr\endcsname}{\usecounter{\@enumctr}% + \def\makelabel##1{\hss\llap{##1}}}\fi} +\def\endenumerate{\endlist}%% +\def\longenum{% + \leftmargin0pt + \ifnum \@enumdepth >3 + \@toodeep + \else + \advance\@enumdepth \@ne + \edef\@enumctr{enum\romannumeral\the\@enumdepth}% + \list{\csname label\@enumctr\endcsname}{% + \usecounter{\@enumctr}% + \labelwidth\z@\leftmargin0pt + \itemindent\parindent\advance\itemindent\labelsep + }% + \fi +} +\let\endlongenum\endlist + +\def\labelenumi{{\rm (}\arabic{enumi}\/{\rm )}} +\def\theenumi{\arabic{enumi}} +\def\labelenumii{{\rm (}\alph{enumii}\rm{)}} +\def\theenumii{\alph{enumii}} +\def\p@enumii{\theenumi} +\def\labelenumiii{\roman{enumiii}.} +\def\theenumiii{\roman{enumiii}} +\def\p@enumiii{\theenumi{\rm (}\theenumii{\rm )}} +\def\labelenumiv{\Alph{enumiv}.} +\def\theenumiv{\Alph{enumiv}} +\def\p@enumiv{\p@enumiii\theenumiii} +\newcommand\labelitemi{\texthyphen}% +\newcommand\labelitemii{\texthyphen}% +\newcommand\labelitemiii{\texthyphen}% +\newcommand\labelitemiv{\texthyphen}% +\font\lcir = lcircle10 at 8pt +\newcommand\bulls{\raise1.5pt\hbox{\lcir\char'162}} +\def\textbullet{\leavevmode\raise2pt\hbox{\bulls}} +\def\texthyphen{---} +\newif\ifhyphen\hyphenfalse + +\def\itemize{% + \ifnum \@itemdepth >3 \@toodeep\else \advance\@itemdepth \@ne + \edef\@itemitem{labelitem\romannumeral\the\@itemdepth}% + \list{\csname\@itemitem\endcsname}% + {\advance\leftmargin-5.7pt\labelsep2pt + \def\makelabel##1{\hss\llap{##1}}}\fi}% +\let\enditemize =\endlist + +\newenvironment{hyphenlist}{% + \hyphentrue + \renewcommand\labelitemi{\texthyphen}% + \renewcommand\labelitemii{\texthyphen}% + \renewcommand\labelitemiii{\texthyphen}% + \renewcommand\labelitemiv{\texthyphen}% + \begin{itemize} +}{% + \end{itemize} + \hyphenfalse} +% +\newenvironment{bulletlist}{% +\leftmargini20pt + \renewcommand\labelitemi{\textbullet}% + \renewcommand\labelitemii{\textbullet}% + \renewcommand\labelitemiii{\textbullet}% + \renewcommand\labelitemiv{\textbullet}% + \begin{itemize} +}{% + \end{itemize}} + +\def\longitem{% + \list{---}{% + \labelwidth\z@ + \leftmargin\z@ + \itemindent\parindent + \advance\itemindent\labelsep + }% +} +\let\endlongitem\endlist +\def\verse{% + \let\\=\@centercr + \list{}{% + \leftmargin 2pc + \itemindent -1.5em + \listparindent \itemindent + \rightmargin\leftmargin + \advance\leftmargin 1.5em + }% + \item[] +} + +\let\endverse\endlist +\def\quotation{% + \list{}{% + \leftmargin 2pc + \listparindent .5em + \itemindent\listparindent + \rightmargin\leftmargin + \parsep \z@ \@plus \p@ + }% + \item[] +} + +\let\endquotation=\endlist +\def\quote{% + \list{}{% + \leftmargin 2pc + \rightmargin\leftmargin + }% + \item[] +} + +\let\endquote=\endlist +% +\def\extractfont{\fontsize{8}{10}\selectfont\leftskip8pt\rightskip8pt} +\newenvironment{extract}{\par\addvspace{7pt plus2pt} +\parindent8pt +\extractfont +\noindent\ignorespaces +}{% +\par\addvspace{6pt plus2pt}} + +\def\descriptionlabel#1{% + \hspace\labelsep \normalfont\itshape #1.% +}% +\newenvironment{description}{% + \list{}{% + \labelwidth\z@ + \let\makelabel\descriptionlabel + } +}{\endlist}% + +\def\describe#1{% + \list{}{% + \listparindent\parindent + \settowidth{\labelwidth}{#1}% + \leftmargin\labelwidth + \addtolength\leftmargin\labelsep + \def\makelabel##1{##1\hfil}% + }% +} +\let\enddescribe\endlist + +\def\program{% + \ifx\@currsize\normalsize + \small + \else + \rm + \fi + \tabbing +} +\let\endprogram\endtabbing + +% Enunciations +\newif\ifitalicenv\italicenvtrue + +\newtheorem{theorem}{Theorem}[section] +\newtheorem{proposition}[theorem]{Proposition} +\newtheorem{lemma}[theorem]{Lemma} +\newtheorem{corollary}[theorem]{Corollary} +% +\newtheorem{exam}[theorem]{Example} +\newenvironment{example}{% +\italicenvfalse +\begin{exam}}{\end{exam}\italicenvtrue} +% +\newtheorem{defi}[theorem]{Definition} +\newenvironment{definition}{% +\italicenvfalse +\begin{defi}}{\end{defi}\italicenvtrue} + +\def\@begintheorem#1#2{% + \trivlist + \item[% + \hskip 12\p@ + \hskip \labelsep + {\ifitalicenv\sc\else\itshape\fi #1\hskip 5\p@\relax{\rm #2}.\enspace}]% + \ifitalicenv\itshape\else\upshape\fi\hskip-\labelsep% +} +\def\@opargbegintheorem#1#2#3{% + \trivlist + \item[\hskip 12pt + \hskip \labelsep + {\ifitalicenv{\sc{#1}}\else{\itshape#1}\fi% + \savebox\@tempboxa{\ifitalicenv{\scshape#3}\else{\itshape#3}\fi}% + \ifdim\wd\@tempboxa>\z@% + \ {\rm #2}\unskip\hskip5pt\relax$($\box\@tempboxa$)$% + \fi.\unskip\hskip5pt}] +\ifitalicenv\itshape\else\upshape\fi\hskip-\labelsep} + +\newif\if@qeded +\global\@qededfalse +\def\proof{% + \global\@qededfalse + \@ifnextchar[{\@xproof}{\@proof}} + +\def\endproof{% + \if@qeded\else\qed\fi + \endtrivlist +} +\def\@proof{% + \trivlist + \item[% + \hskip 12\p@ + \hskip \labelsep + {\sc Proof.\enspace}]\hskip-\labelsep% + \ignorespaces +} +\def\@xproof[#1]{% + \trivlist + \item[\hskip 12\p@\hskip \labelsep{\sc Proof #1.}]% + \ignorespaces +} +\def\qed{\unskip\kern 10pt{\unitlength1pt\linethickness{.4pt}\framebox(5,5){}} + \global\@qededtrue + }% +\def\newdef#1#2{% + \expandafter\@ifdefinable\csname #1\endcsname + {\@definecounter{#1}% + \expandafter\xdef\csname the#1\endcsname{\@thmcounter{#1}}% + \global\@namedef{#1}{\@defthm{#1}{#2}}% + \global\@namedef{end#1}{\@endtheorem}% + }% +} +\def\@defthm#1#2{% + \refstepcounter{#1}% + \@ifnextchar[{\@ydefthm{#1}{#2}}{\@xdefthm{#1}{#2}}% +} +\def\@xdefthm#1#2{% + \@begindef{#2}{\csname the#1\endcsname}% + \ignorespaces +} +\def\@ydefthm#1#2[#3]{% + \trivlist + \item[% + \hskip 10\p@ + \hskip \labelsep + {\it #2% + \savebox\@tempboxa{#3}% + \ifdim \wd\@tempboxa>\z@ + \ \box\@tempboxa + \fi.% + }]% + \ignorespaces +} +\def\@begindef#1#2{% + \trivlist + \item[% + \hskip 10\p@ + \hskip \labelsep + {\it #1\ \rm #2.}% + ]% +} + +% Maths +\def\theequation{\arabic{equation}} + +\def\@marrayclassiv{\@addtopreamble{$\displaystyle \@nextchar$}} +\def\@marrayclassz{\ifcase \@lastchclass \@acolampacol \or \@ampacol \or + \or \or \@addamp \or + \@acolampacol \or \@firstampfalse \@acol \fi +\edef\@preamble{\@preamble + \ifcase \@chnum + \hfil$\relax\displaystyle\@sharp$\hfil \or $\relax\displaystyle\@sharp$\hfil + \or \hfil$\relax\displaystyle\@sharp$\fi}} +\def\marray{\arraycolsep 2.5pt\let\@acol\@arrayacol \let\@classz\@marrayclassz + \let\@classiv\@marrayclassiv \let\\\@arraycr\def\@halignto{}\@tabarray} +\def\endmarray{\crcr\egroup\egroup} + +\arraycolsep 2.5\p@ +\tabcolsep 6\p@ +\arrayrulewidth .25\p@ +\doublerulesep 2\p@ +\tabbingsep \labelsep + +\skip\@mpfootins = \skip\footins +\fboxsep = 3pt \fboxrule = .4\p@ + +% Table of Contents +\def\@pnumwidth{1.55em} +\def\@tocrmarg {2.55em} +\def\@dotsep{4.5} +\setcounter{tocdepth}{3} +\def\tableofcontents{% + \section*{Contents\@mkboth{CONTENTS}{CONTENTS}} + \@starttoc{toc}% +} +\def\l@part#1#2{% + \addpenalty\@secpenalty + \addvspace{2.25em \@plus \p@}% + \begingroup + \@tempdima 3em + \parindent \z@ + \rightskip \@pnumwidth + \parfillskip -\@pnumwidth + {\large \bf \leavevmode #1\hfil \hb@xt@\@pnumwidth{\hss #2}}\par + \nobreak + \endgroup +} +\def\l@section#1#2{% + \addpenalty\@secpenalty + \addvspace{1.0em \@plus \p@}% + \@tempdima 1.5em + \begingroup + \parindent \z@ + \rightskip \@pnumwidth + \parfillskip -\@pnumwidth + \bf \leavevmode #1\hfil \hb@xt@\@pnumwidth{\hss #2}\par + \endgroup +} +\def\l@subsection{\@dottedtocline{2}{1.5em}{2.3em}} +\def\l@subsubsection{\@dottedtocline{3}{3.8em}{3.2em}} + +% List of figures +\def\listoffigures{% + \section*{List of Figures\@mkboth{LIST OF FIGURES}{LIST OF FIGURES}} + \@starttoc{lof}} +\def\l@figure{\@dottedtocline{1}{1.5em}{2.3em}} + +% List of tables +\def\listoftables{% + \section*{List of Tables\@mkboth{LIST OF TABLES}{LIST OF TABLES}} + \@starttoc{lot}} +\let\l@table\l@figure + +% Index +\newif\if@restonecol +\def\theindex{% + \@restonecoltrue + \if@twocolumn \@restonecolfalse \fi + \columnseprule \z@ + \columnsep 35\p@ + \twocolumn[\section*{Index}] + \@mkboth{INDEX}{INDEX}% + \thispagestyle{plain}% + \parindent\z@ + \parskip\z@ \@plus .3\p@\relax + \let\item\@idxitem +} + +\def\endtheindex{% + \if@restonecol + \onecolumn + \else + \clearpage + \fi +} +\def\@idxitem{\par\hangindent 40\p@} +\def\subitem{\par\hangindent 40\p@ \hspace*{20\p@}} +\def\subsubitem{\par\hangindent 40\p@ \hspace*{30\p@}} +\def\indexspace{\par \vskip 10\p@ \@plus 5\p@ \@minus 3\p@\relax} + +% Footnote +\def\footnoterule{% + \kern-3\p@ + \hrule \@width 36\p@ \@height 0.25\p@ + \kern 3\p@ +} +\long\def\@makefntext#1{% + \parindent 1em + \noindent $^{\@thefnmark}$#1% +} + +% Figures and Tables +\newlength\belowcaptionskip +\newlength\abovecaptionskip +\setlength\belowcaptionskip{3.5\p@} +\setlength\abovecaptionskip{6\p@} + +\def\nocaption{\refstepcounter\@captype \par + \vskip 1pc \hbox to\hsize{\hfil \figcaptionnumfont Figure \thefigure + \hfil}} + +\def\FigName{figure}% +\long\def\@caption#1[#2]#3{\par\begingroup + \@parboxrestore + \normalsize + \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}\par + \endgroup} + +\long\def\@makecaption#1#2{% + \ifx\FigName\@captype\baselineskip10pt + \vskip\abovecaptionskip + \setbox\@tempboxa\hbox{\figcaptionfont{\figcaptionnumfont#1}.\hskip7.3pt\relax #2\par}% + \ifdim \wd\@tempboxa >\hsize + \figcaptionfont{\figcaptionnumfont#1}.\hskip7.3pt\relax #2\par + \else + \centerline{\box\@tempboxa}% + \fi + \else% + \setbox\tbbox=\vbox{\hsize\tempdimen\tablecaptionfont{\tablenumfont #1.\ }{#2\par}}% + \setbox\@tempboxa\hbox{\hsize\tempdimen\tablecaptionfont{\tablenumfont #1.}\ {#2\par}}% + \ifdim \wd\@tempboxa >\tempdimen + \centerline{\box\tbbox}% + \else + \centerline{\box\@tempboxa}% + \fi + \vskip\belowcaptionskip + \fi +} +% +\newcounter{figure} +\def\thefigure{\@arabic\c@figure} +\def\fps@figure{tbp} +\def\ftype@figure{1} +\def\ext@figure{lof} +% +\newif\ifcontinued +\global\continuedfalse +% +\def\continued{\global\continuedtrue} +% +\def\fnum@figure{\ifcontinued\global\continuedfalse\addtocounter{figure}{-1} Fig.~\thefigure---{\it Continued}\else Fig.~\thefigure\fi}% +\newenvironment{figure} + {\@float{figure}} + {\end@float} +\newenvironment{figure*} + {\@dblfloat{figure}} + {\end@dblfloat} +% +\newcounter{table} +\renewcommand\thetable{\Roman{table}} +\def\fps@table{tbp} +\def\ftype@table{2} +\def\ext@table{lot} +\def\tablename{Table} +\def\fnum@table{\ifcontinued\addtocounter{table}{-1} Table~\thetable---{\it Continued} \else Table~\thetable\fi} +\newenvironment{table} + {\@float{table}} + {\end@float} +\newenvironment{table*} + {\@dblfloat{table}} + {\end@dblfloat} + +\long\def\tbl#1#2{% +\setbox\tempbox\hbox{\tablefont #2}% +\tabledim\hsize\advance\tabledim by -\wd\tempbox +\tempdimen\wd\tempbox +\global\divide\tabledim\tw@ +\caption{#1\protect\vphantom{yp}} +\centerline{\box\tempbox}}% + +\newenvironment{intexttable}{\par\addvspace{1.2pt plus2pt} +\intexttablefont +}{% +\par\addvspace{7pt plus2pt}} + +\newenvironment{tabnote}{% +\par\vskip5pt +\tabnotefont +\@ifnextchar[{\@tabnote}{\@tabnote[]}}{% +\par} +\def\@tabnote[#1]{\def\@Tempa{#1}\leftskip\tabledim\rightskip\leftskip\ifx\@Tempa\@empty\else{\it #1:}\ \fi\ignorespaces} + +\def\tabnoteentry#1#2{\parindent0pt\par{#1}{#2}} +\def\Note#1#2{\parindent0pt\par{\it #1}\ #2} + +\newdimen\@narrowfig +\newbox\@nfigbox +\newbox\@nfcapbox +\newif\if@nfeven +\def\acmtable#1{% + \@narrowfig #1\relax + \let\caption\@atcap + \let\nocaption\@atnocap + \@ifnextchar[{\@ntab}{\@ntab[\fps@table]}% +} + +\def\@ntab[#1]{% + \expandafter\table\expandafter[#1]% + \setbox\@nfigbox\vbox\bgroup + \hsize \@narrowfig + \@parboxrestore +} + +\def\endacmtable{% + \hb@xt@\textwidth{% + \hfil + \vbox{% + \hsize \@narrowfig + \box\@nfcapbox{% + \baselineskip 4\p@ + \hbox{\vrule \@height .4\p@ \@width \hsize}% + + }% + \vskip -\p@ + \box\@nfigbox + \vskip -\p@ + \begingroup + \baselineskip 4\p@ + \hbox{\vrule \@height .4\p@ \@width \hsize}% + \endgroup + }% + \hfil + }% + \end@float +} +\def\@atmakecap#1#2{% + \setbox\@tempboxa\hbox{#1.\hskip 1em\relax #2}% + \ifdim \wd\@tempboxa >\hsize + \sloppy #1.\hskip 1em\relax #2 \par + \else + \centerline{\box\@tempboxa}% + \fi +} +\def\@atcap{% + \par + \egroup + \refstepcounter\@captype + \@dblarg{\@atcapx\@captype}% +} +\long\def\@atcapx#1[#2]#3{% + \addcontentsline{\csname ext@#1\endcsname}{#1}{% + \protect\numberline{\csname the#1\endcsname}{\ignorespaces #2}% + }% + \setbox\@nfcapbox\vbox{% + \hsize \wd\@nfigbox + \@parboxrestore + \@atmakecap{\csname fnum@#1\endcsname}{\ignorespaces #3}% + \par + }% +} +\def\@atnocap{% + \egroup + \refstepcounter\@captype + \setbox\@nfcapbox\vbox{% + \hsize \wd\@nfigbox + \centerline{\footnotesize \fnum@table} + }% +} +\def\narrowfig#1{% + \@narrowfig #1\relax + \let\caption\@nfcap + \let\nocaption\@nfnocap + \@ifnextchar[{\@nfig}{\@nfig[\fps@figure]}% +} + +\def\@nfig[#1]{% + \expandafter\figure\expandafter[#1]% + \setbox\@nfigbox\vbox\bgroup + \hsize\@narrowfig + \@parboxrestore +} + +\def\endnarrowfig{% + \hb@xt@\textwidth{% + \if@nfeven + \box\@nfcapbox \hfil \box\@nfigbox + \else + \box\@nfigbox \hfil \box\@nfcapbox + \fi + }% + \endfigure +} +\def\@nfcap{% + \par + \egroup + \refstepcounter\@captype + \@dblarg{\@nfcapx\@captype}% +} +\def\@nfmakecap #1#2{% + \setbox\@tempboxa\hbox{#1.\hskip 1em\relax #2}% + \ifdim \wd\@tempboxa >\hsize + \sloppy #1.\hskip 1em\relax #2 \par + \else + \@@line{% + \if@nfeven\else\hfil\fi + \box\@tempboxa + \if@nfeven\hfil\fi + }% + \fi +} +\long\def\@nfcapx#1[#2]#3{% + \addcontentsline{\csname ext@#1\endcsname}{#1}{% + \protect\numberline{\csname the#1\endcsname}{\ignorespaces #2}% + }% + \@seteven + \setbox\@nfcapbox\vbox to \ht\@nfigbox{% + \hsize \textwidth + \advance\hsize -2pc + \advance\hsize -\wd\@nfigbox + \@parboxrestore + \vfil + \@nfmakecap{\csname fnum@#1\endcsname}{\ignorespaces #3}% + \par + \vfil + }% +} +\def\@nfnocap{% + \egroup + \refstepcounter\@captype + \@seteven + \setbox\@nfcapbox\vbox to \ht\@nfigbox{% + \hsize \textwidth + \advance\hsize -2pc + \advance\hsize -\wd\@nfigbox + \@parboxrestore + \vfil + \@@line{% + \if@nfeven\else\hfil\fi + \footnotesize \fnum@figure + \if@nfeven\hfil\fi + }% + \vfil + }% +} + +\def\@seteven{% + \@nfeventrue + \@ifundefined{r@@nf\thefigure}{}{% + \edef\@tmpnf{\csname r@@nf\thefigure\endcsname}% + \edef\@tmpnf{\expandafter\@cdr\@tmpnf\@nil}% + \ifodd\@tmpnf\relax + \@nfevenfalse + \fi + }% + \label{@nf\thefigure}% + \edef\@tmpnfx{\if@nfeven e\else o\fi}% + \edef\@tmpnf{% + \write\@unused{% + \noexpand\ifodd \noexpand\c@page + \noexpand\if \@tmpnfx e% + \noexpand\@nfmsg{\thefigure} + \noexpand\fi + \noexpand\else + \noexpand\if \@tmpnfx o% + \noexpand\@nfmsg{\thefigure}% + \noexpand\fi + \noexpand\fi + }% + }% + \@tmpnf +} + +\def\@nfmsg#1{Bad narrowfig: Figure #1 on page \thepage} +\newbox\@nfigbox +\newbox\@nfcapbox +\newif\if@nfeven + +% Acknowledgments +\newenvironment{ack}{% +\refsection*{ACKNOWLEDGMENT} +\ackfont +}{\par} + +\newenvironment{acks}{% +\refsection*{ACKNOWLEDGMENTS} +\ackfont +}{\par} + +% History Dates +\def\received#1#2#3{\par\addvspace{14\p@}% +{\noindent\fontfamily{\sfdefault}\fontsize{8}{9}\selectfont{Received\ #1;\ revised\ #2;\ accepted\ #3}% +\par}} + +% provide both spellings of Acknowledgment(s) +\let\acknowledgments\acks +\let\endacknowledgments\endacks +\let\acknowledgment\ack +\let\endacknowledgment\endack + +\newcommand{\longpage}{\enlargethispage{\baselineskip}} +\newcommand{\shortpage}{\enlargethispage{-\baselineskip}} + +% Appendices +\newfont{\apbf}{cmbx9} +\def\@withappendix#1{App--\number #1} +\newcommand{\elecappendix}{ +} + +\def\appenheader{\global\@topnum\z@ \global\@botroom \textheight \begin{figure} +\newfont{\sc}{cmcsc10} +\parindent\z@ +\hbox{} +\vskip -\textfloatsep +\vskip 11pt +\hrule height .2pt width 30pc +\vskip 2pt\rule{0pt}{10pt}\ignorespaces} +\def\endappenheader{\end{figure}\gdef\appendixhead{}} + +\def\@appsec{} + +\def\appendix{\par + \setcounter{section}{0} + \setcounter{subsection}{0} + \def\@appsec{APPENDIX } + \def\thesection{\Alph{section}} + \def\theHsection{\Alph{section}}} + +% split electronic appendix into two parts: + +\def\appendixhead#1{\appendix +\section*{ELECTRONIC APPENDIX} +The electronic appendix for this article can be accessed in the ACM Digital Library.} + +\newif\ifelec@app\global\elec@appfalse +\long\def\elecappendix{\immediate\write\@mainaux{\string\lastpage{\the\c@page}}% +\clearpage +\makeatletter +\elec@apptrue +\pagenumbering{withappendix} +\pagestyle{appheadings} +\thispagestyle{titlepage}% +\makeatother +\appendix +{\vbox{\titlefont\parindent0pt\raggedright% +Online Appendix to:\par\@title\par{}}}\vskip 12\p@ +\vbox{\authorfont\parindent0pt\@author{}}\vskip .5em\noindent +\vskip 11pt\noindent +\hrule height .2pt +\par +\def\endbottomstuff{% +\copyrightline\par +\doiline +\vskip-13pt +\strut +\end@float +} +\bottomstuff +\endbottomstuff +} + +%-----------------------BIBLIOGRAPHY STUFF------------------------- +% this is adapted (November 1993) by Andrew Appel and Rebecca Davies from +% +%%% filename = "chicago.sty", +%%% version = "4", % MODIFIED! +%%% date = "31 August 1992", +%%% time = "09:42:44 199", +%%% author = "Glenn Paulley", +%%% address = "Data Structuring Group +%%% Department of Computer Science +%%% University of Waterloo +%%% Waterloo, Ontario, Canada +%%% N2L 3G1", +%%% telephone = "(519) 885-1211", +%%% FAX = "(519) 885-1208", +%%% email = "gnpaulle@bluebox.uwaterloo.ca", + +%%% ==================================================================== +% +% this file: Modification of chicago.sty for new ACM bibliography +% style, which is similar (but not identical) to the ``Chicago'' style. +% +% chicago.sty: Style file for use with bibtex style chicago.bst, for +% bibliographies formatted according to the 13th Edition of the Chicago +% Manual of Style. +% +% 'newapa.bst' was made from 'plain.bst', 'named.bst', and 'apalike.bst', +% with lots of tweaking to make it look like APA style, along with tips +% from Young Ryu and Brian Reiser's modifications of 'apalike.bst'. +% newapa.sty formed the basis of this style, chicago.sty. Author-date +% references in newapa.bst formed the basis for chicago.bst. Chicagoa.bst +% supports annotations. +% +% Version 4 (August, 1992): +% - fixed chicago.bst and chicagoa.bst to handle long author lists in +% sorting +% - fixed chicago.bst and chicagoa.bst so that missing page numbers in +% ``article'' entries are handled correctly +% - modified chicago.sty to format entries with 2nd and subsequent lines +% indented. +% +% Citation format: (author-last-name year) +% (author-last-name and author-last-name year) +% (author-last-name et al. year) +% (author-last-name) +% author-last-name +% author-last-name (year) +% (author-last-name and author-last-name) +% (author-last-name et al.) +% (year) or (year,year) +% year or year,year +% +% Reference list ordering: alphabetical by author or whatever passes +% for author in the absence of one. +% +% This BibTeX style has support for abbreviated author lists and for +% year-only citations. This is done by having the citations +% actually look like +% +% \citeauthoryear{full-author-info}{abbrev-author-info}{year} +% +% The LaTeX style has to have the following (or similar) +% +% \let\@internalcite\cite +% \def\fullcite{\def\citeauthoryear##1##2##3{##1, ##3}\@internalcite} +% \def\fullciteA{\def\citeauthoryear##1##2##3{##1}\@internalcite} +% \def\shortcite{\def\citeauthoryear##1##2##3{##2, ##3}\@internalcite} +% \def\shortciteA{\def\citeauthoryear##1##2##3{##2}\@internalcite} +% \def\citeyear{\def\citeauthoryear##1##2##3{##3}\@internalcite} +% +% +% ------------------------------------------------------------------------- +% +% Citation macros (compatible with natbib package). +% +\AtBeginDocument{% +\@ifpackageloaded{natbib}{% Natbib loaded +\renewcommand\bibsection{% + \refsection*{{\refname}% + \@mkboth{\uppercase{\refname}}{\uppercase{\refname}}% +}}% +\bibpunct[, ]{[}{]}{;}{a}{}{,} +\let\citeN\cite +\let\cite\citep +\let\citeANP\citeauthor +\let\citeNN\citeyearpar +\let\citeyearNP\citeyear +\let\citeyear\citeyearpar +\let\citeNP\citealt +\def\shortcite#1{\citeyear{#1}} +\DeclareRobustCommand\citeA + {\begingroup\NAT@swafalse\let\NAT@ctype\@ne\NAT@partrue\NAT@fullfalse\NAT@open\NAT@citetp} +\newcommand\newblock{} +}{% Natbib not loaded +\let\@internalcite\cite +\def\cite{\def\@citeseppen{-1000}% + \def\@cite##1##2{[##1\if@tempswa , ##2\fi]}% + \def\citeauthoryear##1##2##3{##2 ##3}\@internalcite} +\def\citeXNP#1#2{% + \def\@cite@label{#2}% + \def\@cite##1##2{##1\if@tempswa , ##2\fi}% + \def\citeauthoryear##1##2##3{\@cite@label}\@internalcite{#1}} +\def\citeNP{\def\@citeseppen{-1000}% + \def\@cite##1##2{##1\if@tempswa , ##2\fi}% + \def\citeauthoryear##1##2##3{##2 ##3}\@internalcite} +\def\citeN{\def\@citeseppen{-1000}% + \def\@cite##1##2{##1\if@tempswa , ##2]\else{]}\fi}% + \def\citeauthoryear##1##2##3{##2 [##3}\@citedata} +\def\shortcite#1{\citeyear{#1}} +\def\citeS#1{[\citeANP{#1} \citeyearNP{#1}]} +\def\citeNS#1{\citeANP{#1} \citeyear{#1}} +\def\citeNPS#1{\citeANP{#1} \citeyearNP{#1}} +%testing year,year +\def\citeNN{\def\@citeseppen{-1000}% + \def\@cite##1##2{[##1\if@tempswa , ##2\fi]}% + \def\citeauthoryear##1##2##3{##3}\@citedata} + +\def\citeA{\def\@citeseppen{-1000}% + \def\@cite##1##2{[##1\if@tempswa , ##2\fi]}% + \def\citeauthoryear##1##2##3{##2}\@internalcite} +\def\citeANP{\def\@citeseppen{-1000}% + \def\@cite##1##2{##1\if@tempswa , ##2\fi}% + \def\citeauthoryear##1##2##3{##2}\@internalcite} + +\def\citeyear{\def\@citeseppen{-1000}% + \def\@cite##1##2{[##1\if@tempswa , ##2\fi]}% + \def\citeauthoryear##1##2##3{##3}\@citedata} +\def\citeyearNP{\def\@citeseppen{-1000}% + \def\@cite##1##2{##1\if@tempswa , ##2\fi}% + \def\citeauthoryear##1##2##3{##3}\@citedata} + +% +% \@citedata and \@citedatax: +% +% Place commas in-between citations in the same \citeyear, \citeyearNP, +% or \citeN command. +% Use something like \citeN{ref1,ref2,ref3} and \citeN{ref4} for a list. +% +\def\@citedata{% + \@ifnextchar [{\@tempswatrue\@citedatax}% + {\@tempswafalse\@citedatax[]}% +} + +\def\@citedatax[#1]#2{% +\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi% + \def\@citea{}\@cite{\@for\@citeb:=#2\do% + {\@citea\def\@citea{; }\@ifundefined% by Young + {b@\@citeb}{{\bf ?}% + \@warning{Citation `\@citeb' on page \thepage \space undefined}}% +{\csname b@\@citeb\endcsname}}}{#1}}% + +% don't box citations, separate with ; and a space +% also, make the penalty between citations negative: a good place to break. +% +\def\@citex[#1]#2{% +\if@filesw\immediate\write\@auxout{\string\citation{#2}}\fi% + \def\@citea{}\@cite{\@for\@citeb:=#2\do% + {\@citea\def\@citea{; }\@ifundefined% by Young + {b@\@citeb}{{\bf ?}% + \@warning{Citation `\@citeb' on page \thepage \space undefined}}% +{\csname b@\@citeb\endcsname}}}{#1}}% + +% Fix cite so it doesn't repeat author lists in citations: + +\def\cite{\def\@citeseppen{-1000}% + \def\@cite##1##2{[##1\if@tempswa , ##2\fi]}% + \let\@lastauthor=\@noauthor + \let\citeauthoryear=\citeauthoryear@no@repeats\@internalcite} + %\def\citeauthoryear##1##2##3{##2 ##3}\@internalcite + +\def\@noauthor={\relax} +\let\@lastauthor=\@noauthor +\let\@currauthor=\@noauthor + +\def\citeauthoryear@no@repeats#1#2#3{% + \def\@currauthor{\csname @author #1\endcsname}% + \ifx\@lastauthor\@currauthor{#3}\else{#2 #3}\fi% + \let\@lastauthor=\@currauthor} +}} + +% Bibliography +\let\@biblabel\@gobble +\newdimen\bibindent +\bibindent=16pt +\newcommand\refname{REFERENCES} +\def\thebibliography#1{% + \footnotesize + \refsection*{{\refname} + \@mkboth{\uppercase{\refname}}{\uppercase{\refname}}% + } + \list{}{ + \settowidth\labelwidth{} + \leftmargin0pt + \advance\leftmargin\bibindent + \itemindent -\bibindent + \itemsep2pt + \parsep \z@ + \usecounter{enumi}% + }% + \let\newblock\@empty + \sloppy + \sfcode`\.=1000\relax +} +\let\endthebibliography=\endlist + +% Blackboard font +\DeclareFontFamily{OT1}{ams}{} +\DeclareFontShape{OT1}{ams}{m}{n}{ <-> msam10 }{} +\DeclareFontShape{OT1}{ams}{m}{it}{ <-> msam10 }{} +\DeclareFontShape{OT1}{ams}{bx}{n}{ <-> msbm10 }{} +\DeclareFontShape{OT1}{ams}{bx}{it}{ <-> msbm10 }{} + +\def\bb#1{\mathchoice + {\mbox{\fontfamily{ams}\fontsize{\tf@size}{\tf@size}\selectfont\bf#1}}% + {\mbox{\fontfamily{ams}\fontsize{\tf@size}{\tf@size}\selectfont\bf#1}}% + {\mbox{\fontfamily{ams}\fontsize{\sf@size}{\sf@size}\selectfont\bf#1}}% + {\mbox{\fontfamily{ams}\fontsize{\ssf@size}{\ssf@size}\selectfont\bf#1}}} + +\DeclareMathAlphabet{\mathbb}{OT1}{ams}{bx}{n} +\SetMathAlphabet\mathbb{normal}{OT1}{ams}{bx}{n} +\SetMathAlphabet\mathbb{bold}{OT1}{ams}{bx}{n} +\def\bb{\mathbb} + +\def\text#1{\ifmmode + \mathchoice + {\hbox{\fontsize{\tf@size}{\tf@size}\selectfont#1}}% + {\hbox{\fontsize{\tf@size}{\tf@size}\selectfont#1}}% + {\hbox{\fontsize{\sf@size}{\sf@size}\selectfont#1}}% + {\hbox{\fontsize{\ssf@size}{\ssf@size}\selectfont#1}}% + \else\hbox{\rm#1}\fi} +% +% newdef need to take the optional parameters of newtheorem +\def\newdef#1{\@ifnextchar[{\@xnewdef{#1}}{\@ynewdef{#1}}} +\def\@xnewdef#1[#2]#3{\newtheorem{italic@#1}[#2]{{\em #3}}\@newdef{#1}} +\def\@ynewdef#1#2{\@ifnextchar[{\@xynewdef{#1}{#2}}{\@yynewdef{#1}{#2}}} +\def\@xynewdef#1#2[#3]{\newtheorem{italic@#1}{{\em #2}}[#3]\@newdef{#1}} +\def\@yynewdef#1#2{\newtheorem{italic@#1}{{\em #2}}\@newdef{#1}} +% +\def\@newdef#1{\newenvironment{#1}{\@ifnextchar[{\@xstartdef{#1}}{\@ystartdef{#1}}}{\end{italic@#1}}} +% +\def\@xstartdef#1[#2]{\begin{italic@#1}[{\em #2}]\rm} +\def\@ystartdef#1{\begin{italic@#1}\rm} +% +\newdef{remark}[theorem]{Remark} + +% Page number Panel +\def\openartnum{\vbox to 1.125in{\vskip.125in\vfill\hbox to 26pt{\textcolor{white}{\fontfamily{\sfdefault}\fontsize{12}{7}\selectfont\bfseries\@acmArticle}\hfill}\vfill}} +\def\closeartnum{\vbox to 1.125in{\vskip-.125in\vfill\hbox to 26pt{\textcolor{white}{\fontfamily{\sfdefault}\fontsize{12}{7}\selectfont\bfseries\@acmArticle}\hfill}\vfill}} +\def\artnum{\vbox to 1in{\vfill\hbox to 26pt{\textcolor{white}{\fontfamily{\sfdefault}\fontsize{12}{7}\selectfont\bfseries\@acmArticle}\hfill}\vfill}} +% +\def\opentab{\hbox{\vrule width45.75pt depth0pt height1.125in\hspace*{-35.5pt}\openartnum}} +\def\normtab{\hbox{\vrule width45.75pt depth0pt height1in\hspace*{-35.5pt}\artnum}} +\def\closetab{\hbox{\vrule width45.75pt depth0pt height1.125in\hspace*{-35.5pt}\closeartnum}} +% +\newcommand\tab{\ifcase\@articleSeq\or +\vbox{\vskip-.125in\opentab}\or \vbox{\vskip1in\normtab}\or \vbox{\vskip2in\normtab}\or \vbox{\vskip3in\normtab}\or \vbox{\vskip4in\normtab}\or \vbox{\vskip5in\normtab}\or \vbox{\vskip6in\normtab}\or \vbox{\vskip7in\normtab}\or \vbox{\vskip8in\normtab}\or \vbox{\vskip9in\closetab}\or +\vbox{\vskip-.125in\opentab}\or \vbox{\vskip1in\normtab}\or \vbox{\vskip2in\normtab}\or \vbox{\vskip3in\normtab}\or \vbox{\vskip4in\normtab}\or \vbox{\vskip5in\normtab}\or \vbox{\vskip6in\normtab}\or \vbox{\vskip7in\normtab}\or \vbox{\vskip8in\normtab}\or \vbox{\vskip9in\closetab}\or +\vbox{\vskip-.125in\opentab}\or \vbox{\vskip1in\normtab}\or \vbox{\vskip2in\normtab}\or \vbox{\vskip3in\normtab}\or \vbox{\vskip4in\normtab}\or \vbox{\vskip5in\normtab}\or \vbox{\vskip6in\normtab}\or \vbox{\vskip7in\normtab}\or \vbox{\vskip8in\normtab}\or \vbox{\vskip9in\closetab}\fi} + +% Output Routine +\def\@outputpage{% +\begingroup % the \endgroup is put in by \aftergroup + \let \protect \noexpand + \@resetactivechars + \@parboxrestore + \shipout \vbox{% + \set@typeset@protect + \aftergroup \endgroup + \aftergroup \set@typeset@protect + % correct? or just restore by ending + % the group? + \if@specialpage + \global\@specialpagefalse\@nameuse{ps@\@specialstyle}% + \fi + \if@twoside + \ifodd\count\z@ \let\@thehead\@oddhead \let\@thefoot\@oddfoot + \let\@themargin\oddsidemargin + \else \let\@thehead\@evenhead + \let\@thefoot\@evenfoot \let\@themargin\evensidemargin + \fi + \fi + \reset@font + \normalsize + \normalsfcodes + \let\label\@gobble + \let\index\@gobble + \let\glossary\@gobble + \baselineskip\z@skip \lineskip\z@skip \lineskiplimit\z@ + \@begindvi + \ifelec@app\else\ifnum\c@page=1\vbox to 0pt{\hbox to \trimwidth{\hfill\tab}}\fi\fi + \vskip \topmargin + \moveright\@themargin \vbox {% + \setbox\@tempboxa \vbox to\headheight{% + \vfil + \color@hbox + \normalcolor + \hb@xt@\textwidth{\@thehead}% + \color@endbox + }% %% 22 Feb 87 + \dp\@tempboxa \z@ + \box\@tempboxa + \vskip \headsep + \box\@outputbox + \baselineskip \footskip + \color@hbox + \normalcolor + \hb@xt@\textwidth{\@thefoot}% + \color@endbox + }% + }% + \global \@colht \textheight + \stepcounter{page}% + \let\firstmark\botmark +} +% +\ps@headings +\pagenumbering{arabic} +\onecolumn + +\frenchspacing +\sloppy +\widowpenalty10000 +\clubpenalty10000 + +\endinput + +% End of file `acmsmall.cls' Version 1.1 + diff --git a/doc/algorithm.sty b/doc/algorithm.sty new file mode 100644 index 0000000000000000000000000000000000000000..34e1f1fd02828b103f716f623c83f5399bc1ce75 --- /dev/null +++ b/doc/algorithm.sty @@ -0,0 +1,96 @@ +% ALGORITHM STYLE -- Released 8 April 1996 +% for LaTeX-2e +% Copyright -- 1994 Peter Williams +% +% E-mail pwil3058@bigpond.net.au +% +% This style file is free software; you can redistribute it and/or +% modify it under the terms of the GNU Lesser General Public +% License as published by the Free Software Foundation; either +% version 2 of the License, or (at your option) any later version. +% +% This style file 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 +% Lesser General Public License for more details. +% +% You should have received a copy of the GNU Lesser General Public +% License along with this style file; if not, write to the +% Free Software Foundation, Inc., 59 Temple Place - Suite 330, +% Boston, MA 02111-1307, USA. +% +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{algorithm} +\typeout{Document Style `algorithm' - floating environment} + +\RequirePackage{float} +\RequirePackage{ifthen} +\newcommand{\ALG@within}{nothing} +\newboolean{ALG@within} +\setboolean{ALG@within}{false} +\newcommand{\ALG@floatstyle}{ruled} +\newcommand{\ALG@name}{Algorithm} +\newcommand{\listalgorithmname}{List of \ALG@name s} + +% Declare Options +% first appearance +\DeclareOption{plain}{ + \renewcommand{\ALG@floatstyle}{plain} +} +\DeclareOption{ruled}{ + \renewcommand{\ALG@floatstyle}{ruled} +} +\DeclareOption{boxed}{ + \renewcommand{\ALG@floatstyle}{boxed} +} +% then numbering convention +\DeclareOption{part}{ + \renewcommand{\ALG@within}{part} + \setboolean{ALG@within}{true} +} +\DeclareOption{chapter}{ + \renewcommand{\ALG@within}{chapter} + \setboolean{ALG@within}{true} +} +\DeclareOption{section}{ + \renewcommand{\ALG@within}{section} + \setboolean{ALG@within}{true} +} +\DeclareOption{subsection}{ + \renewcommand{\ALG@within}{subsection} + \setboolean{ALG@within}{true} +} +\DeclareOption{subsubsection}{ + \renewcommand{\ALG@within}{subsubsection} + \setboolean{ALG@within}{true} +} +\DeclareOption{nothing}{ + \renewcommand{\ALG@within}{nothing} + \setboolean{ALG@within}{true} +} +\DeclareOption*{\edef\ALG@name{\CurrentOption}} + +% ALGORITHM +% +\ProcessOptions +\floatstyle{\ALG@floatstyle} +\ifthenelse{\boolean{ALG@within}}{ + \ifthenelse{\equal{\ALG@within}{part}} + {\newfloat{algorithm}{htbp}{loa}[part]}{} + \ifthenelse{\equal{\ALG@within}{chapter}} + {\newfloat{algorithm}{htbp}{loa}[chapter]}{} + \ifthenelse{\equal{\ALG@within}{section}} + {\newfloat{algorithm}{htbp}{loa}[section]}{} + \ifthenelse{\equal{\ALG@within}{subsection}} + {\newfloat{algorithm}{htbp}{loa}[subsection]}{} + \ifthenelse{\equal{\ALG@within}{subsubsection}} + {\newfloat{algorithm}{htbp}{loa}[subsubsection]}{} + \ifthenelse{\equal{\ALG@within}{nothing}} + {\newfloat{algorithm}{htbp}{loa}}{} +}{ + \newfloat{algorithm}{htbp}{loa} +} +\floatname{algorithm}{\ALG@name} + +\newcommand{\listofalgorithms}{\listof{algorithm}{\listalgorithmname}} + diff --git a/doc/algorithmic.sty b/doc/algorithmic.sty new file mode 100644 index 0000000000000000000000000000000000000000..a8ea2546bc7e7a21bd2c067b4e54c1cbace9e365 --- /dev/null +++ b/doc/algorithmic.sty @@ -0,0 +1,192 @@ +% ALGORITHMIC STYLE for LaTeX version 2e +% +% This style file is free software; you can redistribute it and/or +% modify it under the terms of the GNU Lesser General Public +% License as published by the Free Software Foundation; either +% version 2 of the License, or (at your option) any later version. +% +% This style file 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 +% Lesser General Public License for more details. +% +% You should have received a copy of the GNU Lesser General Public +% License along with this style file; if not, write to the +% Free Software Foundation, Inc., 59 Temple Place - Suite 330, +% Boston, MA 02111-1307, USA. +% +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{algorithmic}[2006/06/02] +\typeout{Document Style `algorithmic' - environment} +% +\RequirePackage{ifthen} +\RequirePackage{calc} +\RequirePackage{keyval} +\newboolean{ALC@noend} +\setboolean{ALC@noend}{false} +\newcounter{ALC@line} +\newcounter{ALC@rem} +\newcounter{ALC@depth} +\newlength{\ALC@tlm} +% +\DeclareOption{noend}{\setboolean{ALC@noend}{true}} +% +\ProcessOptions +% +% For keyval-style options +\def\algsetup{\setkeys{ALG}} +% +% For indentation of algorithms +\newlength{\algorithmicindent} +\setlength{\algorithmicindent}{0pt} +\define@key{ALG}{indent}{\setlength{\algorithmicindent}{#1}} +\ifthenelse{\lengthtest{\algorithmicindent=0pt}}% + {\setlength{\algorithmicindent}{1em}}{} +% +% For line numbers' delimiters +\newcommand{\ALC@linenodelimiter}{:} +\define@key{ALG}{linenodelimiter}{\renewcommand{\ALC@linenodelimiter}{#1}} + +% +% For line numbers' size +\newcommand{\ALC@linenosize}{\footnotesize} +\define@key{ALG}{linenosize}{\renewcommand{\ALC@linenosize}{#1}} + +% +% ALGORITHMIC +\newcommand{\algorithmicrequire}{\textbf{Require:}} +\newcommand{\algorithmicensure}{\textbf{Ensure:}} +\newcommand{\algorithmiccomment}[1]{\{#1\}} +\newcommand{\algorithmicend}{\textbf{end}} +\newcommand{\algorithmicif}{\textbf{if}} +\newcommand{\algorithmicthen}{\textbf{then}} +\newcommand{\algorithmicelse}{\textbf{else}} +\newcommand{\algorithmicelsif}{\algorithmicelse\ \algorithmicif} +\newcommand{\algorithmicendif}{\algorithmicend\ \algorithmicif} +\newcommand{\algorithmicfor}{\textbf{for}} +\newcommand{\algorithmicforall}{\textbf{for all}} +\newcommand{\algorithmicdo}{\textbf{do}} +\newcommand{\algorithmicendfor}{\algorithmicend\ \algorithmicfor} +\newcommand{\algorithmicwhile}{\textbf{while}} +\newcommand{\algorithmicendwhile}{\algorithmicend\ \algorithmicwhile} +\newcommand{\algorithmicloop}{\textbf{loop}} +\newcommand{\algorithmicendloop}{\algorithmicend\ \algorithmicloop} +\newcommand{\algorithmicrepeat}{\textbf{repeat}} +\newcommand{\algorithmicuntil}{\textbf{until}} +\newcommand{\algorithmicprint}{\textbf{print}} +\newcommand{\algorithmicreturn}{\textbf{return}} +\newcommand{\algorithmictrue}{\textbf{true}} +\newcommand{\algorithmicfalse}{\textbf{false}} +\def\ALC@setref{% + \def\@currentlabel{\theALC@line}% +} +\def\ALC@item[#1]{% +\if@noparitem \@donoparitem + \else \if@inlabel \indent \par \fi + \ifhmode \unskip\unskip \par \fi + \if@newlist \if@nobreak \@nbitem \else + \addpenalty\@beginparpenalty + \addvspace\@topsep \addvspace{-\parskip}\fi + \else \addpenalty\@itempenalty \addvspace\itemsep + \fi + \global\@inlabeltrue +\fi +\everypar{\global\@minipagefalse\global\@newlistfalse + \if@inlabel\global\@inlabelfalse \hskip -\parindent \box\@labels + \penalty\z@ \fi + \everypar{}}\global\@nobreakfalse +\if@noitemarg \@noitemargfalse \if@nmbrlist \refstepcounter{\@listctr}\fi \fi +\sbox\@tempboxa{\makelabel{#1}}% +\global\setbox\@labels + \hbox{\unhbox\@labels \hskip \itemindent + \hskip -\labelwidth \hskip -\ALC@tlm + \ifdim \wd\@tempboxa >\labelwidth + \box\@tempboxa + \else \hbox to\labelwidth {\unhbox\@tempboxa}\fi + \hskip \ALC@tlm}\ignorespaces} +% +\newenvironment{algorithmic}[1][0]{ +\setcounter{ALC@depth}{\@listdepth}% +\let\@listdepth\c@ALC@depth% +\let\@item\ALC@item% + \newcommand{\ALC@lno}{% +\ifthenelse{\equal{\arabic{ALC@rem}}{0}} +{{\ALC@linenosize \arabic{ALC@line}\ALC@linenodelimiter}}{}% +} +\let\@listii\@listi +\let\@listiii\@listi +\let\@listiv\@listi +\let\@listv\@listi +\let\@listvi\@listi +\let\@listvii\@listi + \newenvironment{ALC@g}{ + \begin{list}{\ALC@lno}{ \itemsep\z@ \itemindent\z@ + \listparindent\z@ \rightmargin\z@ + \topsep\z@ \partopsep\z@ \parskip\z@\parsep\z@ + \leftmargin \algorithmicindent%1em + \addtolength{\ALC@tlm}{\leftmargin} + } + } + {\end{list}} + \newcommand{\ALC@it}{\refstepcounter{ALC@rem}\refstepcounter{ALC@line}\ifthenelse{\equal{\arabic{ALC@rem}}{#1}}{\setcounter{ALC@rem}{0}}{}\item\ALC@setref} + \newcommand{\ALC@com}[1]{\ifthenelse{\equal{##1}{default}}% +{}{\ \algorithmiccomment{##1}}} + \newcommand{\REQUIRE}{\item[\algorithmicrequire]} + \newcommand{\ENSURE}{\item[\algorithmicensure]} + \newcommand{\PRINT}{\ALC@it\algorithmicprint{}\ \ } + \newcommand{\RETURN}{\ALC@it\algorithmicreturn{}\ \ } + \newcommand{\TRUE}{\algorithmictrue{}} + \newcommand{\FALSE}{\algorithmicfalse{}} + \newcommand{\STATE}{\ALC@it} + \newcommand{\STMT}{\ALC@it} + \newcommand{\COMMENT}[1]{\algorithmiccomment{##1}} + \newenvironment{ALC@if}{\begin{ALC@g}}{\end{ALC@g}} + \newenvironment{ALC@for}{\begin{ALC@g}}{\end{ALC@g}} + \newenvironment{ALC@whl}{\begin{ALC@g}}{\end{ALC@g}} + \newenvironment{ALC@loop}{\begin{ALC@g}}{\end{ALC@g}} + \newenvironment{ALC@rpt}{\begin{ALC@g}}{\end{ALC@g}} + \renewcommand{\\}{\@centercr} + \newcommand{\IF}[2][default]{\ALC@it\algorithmicif\ ##2\ \algorithmicthen% +\ALC@com{##1}\begin{ALC@if}} + \newcommand{\ELSE}[1][default]{\end{ALC@if}\ALC@it\algorithmicelse% +\ALC@com{##1}\begin{ALC@if}} + \newcommand{\ELSIF}[2][default]% +{\end{ALC@if}\ALC@it\algorithmicelsif\ ##2\ \algorithmicthen% +\ALC@com{##1}\begin{ALC@if}} + \newcommand{\FOR}[2][default]{\ALC@it\algorithmicfor\ ##2\ \algorithmicdo% +\ALC@com{##1}\begin{ALC@for}} + \newcommand{\FORALL}[2][default]{\ALC@it\algorithmicforall\ ##2\ % +\algorithmicdo% +\ALC@com{##1}\begin{ALC@for}} + \newcommand{\WHILE}[2][default]{\ALC@it\algorithmicwhile\ ##2\ % +\algorithmicdo% +\ALC@com{##1}\begin{ALC@whl}} + \newcommand{\LOOP}[1][default]{\ALC@it\algorithmicloop% +\ALC@com{##1}\begin{ALC@loop}} + \newcommand{\REPEAT}[1][default]{\ALC@it\algorithmicrepeat% +\ALC@com{##1}\begin{ALC@rpt}} + \newcommand{\UNTIL}[1]{\end{ALC@rpt}\ALC@it\algorithmicuntil\ ##1} + \ifthenelse{\boolean{ALC@noend}}{ + \newcommand{\ENDIF}{\end{ALC@if}} + \newcommand{\ENDFOR}{\end{ALC@for}} + \newcommand{\ENDWHILE}{\end{ALC@whl}} + \newcommand{\ENDLOOP}{\end{ALC@loop}} + }{ + \newcommand{\ENDIF}{\end{ALC@if}\ALC@it\algorithmicendif} + \newcommand{\ENDFOR}{\end{ALC@for}\ALC@it\algorithmicendfor} + \newcommand{\ENDWHILE}{\end{ALC@whl}\ALC@it\algorithmicendwhile} + \newcommand{\ENDLOOP}{\end{ALC@loop}\ALC@it\algorithmicendloop} + } + \renewcommand{\@toodeep}{} + \begin{list}{\ALC@lno}{\setcounter{ALC@rem}{0}\setcounter{ALC@line}{0}% + \itemsep\z@ \itemindent\z@ \listparindent\z@% + \partopsep\z@ \parskip\z@ \parsep\z@% + \labelsep 0.5em \topsep 0.2em% +\ifthenelse{\equal{#1}{0}} + {\labelwidth 0.5em } + {\labelwidth 1.2em } +\leftmargin\labelwidth \addtolength{\leftmargin}{\labelsep} + \ALC@tlm\labelsep + } +} +{\end{list}} diff --git a/doc/codes-best-practices.tex b/doc/codes-best-practices.tex new file mode 100644 index 0000000000000000000000000000000000000000..46c9ea265c11c30aabea411a730fb5abc5bf3628 --- /dev/null +++ b/doc/codes-best-practices.tex @@ -0,0 +1,571 @@ + +\documentclass[conference,10pt,compsocconf,onecolumn]{IEEEtran} +%\documentclass{acm_proc_article-sp} +%\documentclass{sig-alternate} +% Add the compsoc option for Computer Society conferences. +% +% If IEEEtran.cls has not been installed into the LaTeX system files, +% manually specify the path to it like: +% \documentclass[conference]{../sty/IEEEtran} + +% *** CITATION PACKAGES *** +% +\usepackage{cite} +% cite.sty was written by Donald Arseneau +% V1.6 and later of IEEEtran pre-defines the format of the cite.sty package +% \cite{} output to follow that of IEEE. Loading the cite package will +% result in citation numbers being automatically sorted and properly +% "compressed/ranged". e.g., [1], [9], [2], [7], [5], [6] without using +% cite.sty will become [1], [2], [5]--[7], [9] using cite.sty. cite.sty's +% \cite will automatically add leading space, if needed. Use cite.sty's +% noadjust option (cite.sty V3.8 and later) if you want to turn this off. +% cite.sty is already installed on most LaTeX systems. Be sure and use +% version 4.0 (2003-05-27) and later if using hyperref.sty. cite.sty does +% not currently provide for hyperlinked citations. +% The latest version can be obtained at: +% http://www.ctan.org/tex-archive/macros/latex/contrib/cite/ +% The documentation is contained in the cite.sty file itself. +% +\usepackage{setspace} +\usepackage{wrapfig} +\usepackage{color} +\usepackage{listing} +\usepackage{listings} +\usepackage{verbatim} + +\lstset{ % +frame=single, +language=C, +captionpos=b, +columns=fullflexible, +morekeywords={aesop,pwait,pbranch,pbreak}, +numbers=left, +basicstyle=\scriptsize\ttfamily, +breaklines=true, +framexleftmargin=0em, +boxpos=c, +resetmargins=true, +xleftmargin=6ex +%basicstyle=\footnotesize +} + + +\usepackage[pdftex]{graphicx} +%\usepackage{graphicx} +% declare the path(s) where your graphic files are +\graphicspath{{./}{data/beagle/}} +% and their extensions so you won't have to specify these with +% every instance of \includegraphics +\DeclareGraphicsExtensions{.pdf,.jpeg,.png} + +% *** GRAPHICS RELATED PACKAGES *** +% +\ifCLASSINFOpdf + % \usepackage[pdftex]{graphicx} + % declare the path(s) where your graphic files are + % \graphicspath{{../pdf/}{../jpeg/}} + % and their extensions so you won't have to specify these with + % every instance of \includegraphics + % \DeclareGraphicsExtensions{.pdf,.jpeg,.png} +\else + % or other class option (dvipsone, dvipdf, if not using dvips). graphicx + % will default to the driver specified in the system graphics.cfg if no + % driver is specified. + % \usepackage[dvips]{graphicx} + % declare the path(s) where your graphic files are + % \graphicspath{{../eps/}} + % and their extensions so you won't have to specify these with + % every instance of \includegraphics + % \DeclareGraphicsExtensions{.eps} +\fi + +% *** ALIGNMENT PACKAGES *** +% +%\usepackage{array} +% Frank Mittelbach's and David Carlisle's array.sty patches and improves +% the standard LaTeX2e array and tabular environments to provide better +% appearance and additional user controls. As the default LaTeX2e table +% generation code is lacking to the point of almost being broken with +% respect to the quality of the end results, all users are strongly +% advised to use an enhanced (at the very least that provided by array.sty) +% set of table tools. array.sty is already installed on most systems. The +% latest version and documentation can be obtained at: +% http://www.ctan.org/tex-archive/macros/latex/required/tools/ + +%\usepackage{eqparbox} +% Also of notable interest is Scott Pakin's eqparbox package for creating +% (automatically sized) equal width boxes - aka "natural width parboxes". +% Available at: +% http://www.ctan.org/tex-archive/macros/latex/contrib/eqparbox/ + +\usepackage{algorithm} +\usepackage[noend]{algorithmic} + +% *** SUBFIGURE PACKAGES *** +\usepackage[tight,footnotesize]{subfigure} +% \usepackage{subfigure} +% subfigure.sty was written by Steven Douglas Cochran. This package makes it +% easy to put subfigures in your figures. e.g., "Figure 1a and 1b". For IEEE +% work, it is a good idea to load it with the tight package option to reduce +% the amount of white space around the subfigures. subfigure.sty is already +% installed on most LaTeX systems. The latest version and documentation can +% be obtained at: +% http://www.ctan.org/tex-archive/obsolete/macros/latex/contrib/subfigure/ +% subfigure.sty has been superceeded by subfig.sty. + +%\usepackage[caption=false]{caption} +%\usepackage[font=footnotesize]{subfig} +% subfig.sty, also written by Steven Douglas Cochran, is the modern +% replacement for subfigure.sty. However, subfig.sty requires and +% automatically loads Axel Sommerfeldt's caption.sty which will override +% IEEEtran.cls handling of captions and this will result in nonIEEE style +% figure/table captions. To prevent this problem, be sure and preload +% caption.sty with its "caption=false" package option. This is will preserve +% IEEEtran.cls handing of captions. Version 1.3 (2005/06/28) and later +% (recommended due to many improvements over 1.2) of subfig.sty supports +% the caption=false option directly: +%\usepackage[caption=false,font=footnotesize]{subfig} +% +% The latest version and documentation can be obtained at: +% http://www.ctan.org/tex-archive/macros/latex/contrib/subfig/ +% The latest version and documentation of caption.sty can be obtained at: +% http://www.ctan.org/tex-archive/macros/latex/contrib/caption/ + +% *** PDF, URL AND HYPERLINK PACKAGES *** +% +\usepackage{url} +% url.sty was written by Donald Arseneau. It provides better support for +% handling and breaking URLs. url.sty is already installed on most LaTeX +% systems. The latest version can be obtained at: +% http://www.ctan.org/tex-archive/macros/latex/contrib/misc/ +% Read the url.sty source comments for usage information. Basically, +% \url{my_url_here}. + +% *** Do not adjust lengths that control margins, column widths, etc. *** +% *** Do not use packages that alter fonts (such as pslatex). *** +% There should be no need to do such things with IEEEtran.cls V1.6 and later. +% (Unless specifically asked to do so by the journal or conference you plan +% to submit to, of course. ) + +% correct bad hyphenation here +\hyphenation{op-tical net-works semi-conduc-tor} + +\newcommand{\codesmapping}[1]{\texttt{codes\_mapping}} +\newcommand{\codesconfig}[1]{\texttt{codes\_config}} +\newcommand{\codesmodelnet}[1]{\texttt{model\_net}} + + +\begin{document} +\title{CODES Best Practices} + +%\author{\IEEEauthorblockN{Someone\IEEEauthorrefmark{1}} \\ +%\IEEEauthorblockA{\IEEEauthorrefmark{1}Somewhere} +%} + +%\numberofauthors{6} % in this sample file, there are a *total* + + +% use for special paper notices +%\IEEEspecialpapernotice{(Invited Paper)} + +% use arabic rather than roman numerals for table references +\renewcommand{\thetable}{\arabic{table}} + +% make the title area +\maketitle + +\begin{abstract} +This document outlines best practices for developing models in the +CODES/ROSS framework. The reader should already be familiar with ROSS +and discrete event simulation in general; those topics are covered in the primary +ROSS documentation. Additionally, the GETTING\_STARTED file presents a better +introduction/overview to CODES - this guide should be consulted after becoming +familiar with CODES/ROSS. +% +The main purpose of this document is to help the reader produce +CODES models in a consistent, modular style so that components can be more +easily shared and reused. It also includes a few tips to help avoid common +simulation bugs. + +For more information, ROSS has a bunch of documentation available in their +repository/wiki - see \url{https://github.com/carothersc/ROSS}. +\end{abstract} + +\section{CODES: modularizing models} + +This section covers some of the basic principles of how to organize model +components to be more modular and easier to reuse across CODES models. + +\subsection{Units of time} + +ROSS does not dictate the units to be used in simulation timestamps. +The \texttt{tw\_stime} type could represent any time unit +(e.g. days, hours, seconds, nanoseconds, etc.). When building CODES +models you should \emph{always treat timestamps as double precision floating +point numbers representing nanoseconds}, however. +All components within a model must agree on the time units in order to +advance simulation time consistently. Several common utilities in the +CODES project expect to operate in terms of nanoseconds. + +\subsection{Organizing models by LP types} + +ROSS allows you to use as many different LP types as you would like to +construct your models. Try to take advantage of this as much as possible by +organizing your simulation so that each component of the system that you are +modeling is implemented within its own LP type. For example, a storage +system model might use different LPs for hard disks, clients, network +adapters, and servers. There are multiple reasons for dividing up models +like this: + +\begin{itemize} +\item General modularity: makes it easier to pull out particular components +(for example, a disk model) for use in other models. +\item Simplicity: if each LP type is only handling a limited set of +events, then the event structure, state structure, and event handler +functions will all be much smaller and easier to understand. +\item Reverse computation: it makes it easier to implement reverse +computation, not only because the code is simpler, but also because you can +implement and test reverse computation per component rather than having to +apply it to an entire model all at once before testing. +\end{itemize} + +It is also important to note that you can divide up models not just by +hardware components, but also by functionality, just as +you would modularize the implementation of a distributed file system. For +example, a storage daemon might include separate LPs for replication, failure +detection, and reconstruction. Each of those LPs can share the same network +card and disk resources for accurate modeling of resource usage. They key +reason for splitting them up is to simplify the model and to encourage +reuse. + +One hypothetical downside to splitting up models into multiple LP types is that it likely +means that your model will generate more events than a monolithic model +would have. Remember that \emph{ROSS is really efficient at generating and +processing events}, though! It is usually a premature optimization to try to optimize a model by +replacing events with function calls in cases where you know the necessary +data is available on the local MPI process. Also recall that any information +exchanged via event automatically benefits by shifting burden for +tracking/retaining event data and event ordering into ROSS rather than your +model. This can help simplify reverse computation by breaking complex +operations into smaller, easier to understand (and reverse) event units with +deterministic ordering. + +\subsection{Sharing message representation} + +It is often difficult to debug cases where an LP sends a message to the wrong +LP, as the event structures can be completely different. Hence, it greatly aids +debugging to adhere to a common structure in messages. In particular, the +message header struct \texttt{msg\_header} in lp-msg.h should be placed and +used at the top of every LP's event structure, enabling inspection of any kind +of message in the simulation. The ``magic'' number should be unique to each LP +type to delineate what the expected type of the intended LP recipient. It is a +similarly good idea to use unique event type IDs. + +\subsection{Providing a sane communication API between LPs} + +ROSS operates by exchanging events between LPs. If an LP is sending +an event to another LP of the same type, then in general it can do so +by allocating an event structure (e.g. \texttt{tw\_event\_new()}), +populating the event structure, and transmitting it +(e.g. \texttt{tw\_event\_send()}). If an LP is sending an event to +another LP of a \emph{different} type, however, then it should use an +explicit API to do so without exposing the other LP's event structure +definition. Event structures are not a robust API for exchanging data +across different LP types. If one LP type accesses the event (or state) +structure of another LP type, then it entangles the two components such +that one LP is dependent upon the internal architecture of another LP. +This not only makes it difficult to reuse components, but also makes it +difficult to check for incompatibilities at compile time. The compiler +has no way to know which fields in a struct must be set before sending +an event. + +For these reasons we encourage that a) each LP be implemented in a separate +source file and b) all event structs and state structs +be defined only within those source files. They should not be exposed in external +headers. If the definitions are placed in a header then it makes it +possible for those event and state structs to be used as an ad-hoc interface +between LPs of different types. + +\section{Coping with time warp / reverse computation} + +Time warp and ROSS's reverse computation mechanism, while vital to providing +scalable simulation performance, also complicates model development and +debugging. This section lists some ways of coping with these kinds of errors, +and with reverse computation in general. + +The time warp protocol is susceptible to certain classes of simulation behavior +by which LPs are asked to perform messages that are potentially outside the +scope of the behavior the programmer intended to perform (not including logic +bugs by the programmer). An excellent discussion of this topic is given in the +paper ``The Dark Side of Risk (What your mother never told you about Time +Warp)'' by Nicol and Liu +(\url{http://ieeexplore.ieee.org/xpls/abs_all.jsp?arnumber=594606}). + +As a small example, consider two LPs, $A$ and $B$. Say $A$ has sent some +message to $B$ at some logical time $t$, then at $t+1$, $A$ is rolled back and +sends an anti-message to $B$. However, before $B$ can process the anti-message, +it processes the original message sent by $A$ *and* sends a message back to +$A$. Now, $A$ receives a message that resulted from a state that, in $A$'s +view, is undefined/unexpected. + +Depending on the event dependencies between LPs, issues such as the example can +easily occur in optimistic simulations. In general, when diagnosing these +issues it is useful to determine the full flow of events coming into an LP and +ordering dependencies between those events. For example, protocols for +performing a distributed storage write may have a number of steps represented +as events. Knowing the order that these events can arrive in the system, and +whether multiple events from e.g.\ different writes are possible can go a +long way in determining the vectors for possible errors. + +\subsection{Self-suspend} + +Self-suspend is a technique for limiting how far down a path of undefined +behavior an LP goes when receiving unexpected/undefined combinations of events. +It is a relatively simple concept that falls into four steps: +\begin{enumerate} + \item Aggressively check events for potential unexpected input, putting the + LP into \emph{suspend mode} by setting a suspend counter and returning + (keeping the LP state as it was before the offending event was + processed). Typically these can intersect with asserts in LP code, but + it is often unclear whether a model error is a programmer error or a + result of time warp event ordering. + \item While the suspend counter is positive, increment upon forward event + receipt and decrement upon reverse event receipt. Don't process the + received events. + \item When the suspend counter returns to zero, start processing forward + events again as normal. + \item Report whether an LP is in suspend state at the end of the + simulation. +\end{enumerate} + +The primary benefit of self-suspend is that it prevents arbitrary changing (or +destructing) of state based on unexpected messages, leading to a much more +stable simulation. Additionally, the machinery for self-suspend is easy to +implement -- steps 2--4 are a few lines of code each. Also, LP-IO can be +used upon encountering a suspend condition to give error specifics (the reverse +write would occur in the reverse handler in step 3). + +\subsection{Stash data needed for reverse computation within event structures} + +Writing discrete-event simulations will necessarily involve ``destructive'' +operations, which, in the view of an optimistic simulation, are operations in +which the information needed for rollback is no longer available. Destructive +operations include: +\begin{enumerate} + \item Re-assignment of a variable (losing the original value) + \item Most floating point operations. Floating-point math is not + associative and rounding errors cause issues such as + $a+b-b \neq a$, which need to be considered when making a simulation + that involves floating-point math. + \item \texttt{free}'ing data. +\end{enumerate} + +One nice property of events is that the data in an event structure will stick +around until GVT sweeps by and the event is guaranteed to be no longer needed. +Hence, one strategy for rolling back destructive operations is to stash the +original values in the event structures causing the destruction, and restoring +them upon rollback. The primary downside of this is that event structure size +increases, which increases ROSS-related overheads (manipulating event-related +data structures and sending events to other processes). + +\subsection{Prefer static to dynamic memory in LP state} + +In many cases (such as implementing data structures like queues and stacks), an +LP will want to malloc memory within in an event and free it within another. +This is discouraged for the time being. Once a piece of data is freed, it +cannot be recovered upon rollback later on. If your data structures being +allocated are simple and relatively small, you can put the data to be freed +directly into the event structure then free the original copy, though it will +increase the event structure size for the LP accordingly. + +In the future, optimistic-mode-aware free lists may be provided by ROSS that +will mitigate this problem. At the moment, a manual implementation of this is +provided in codes by codes/rc-stack.h (see tests/rc-stack-test.c for a +simple demonstration). + +\subsection{Handling non-trivial event dependencies: queuing example} + +In storage system simulations, it will often be the case that clients, servers, +or both issue multiple asynchronous (parallel) operations, performing some +action upon the completion of them. More generally, the problem is: an event +issuance (an ack to the client) is based on the completion of more than one +asynchronous/parallel events (local write on primary server, forwarding write to +replica server). Further complicating the matter for storage simulations, there +can be any number of outstanding requests, each waiting on multiple events. + +In ROSS's sequential and conservative parallel modes, the necessary state can +easily be stored in the LP as a queue of statuses for each set of events, +enqueuing upon asynchronous event issuances and updating/dequeuing upon each +completion. Each LP can assign unique IDs to each queue item and propagate the +IDs through the asynchronous events for lookup purposes. However, in optimistic +mode we may remove an item from the queue and then be forced to re-insert it +during reverse computation. + +Naively, one could simply never remove queue items, but of course memory will +quickly be consumed. + +An elegant solution to this is to \emph{cache the status state in the event +structure that causes the dequeue}. ROSS's reverse computation semantics ensures +that this event will be reversed before the completion events of any of the +other asynchronous events, allowing us to easily recover the state. Furthermore, +events are garbage-collected as the GVT, reducing memory management complexity. +However, this strategy has the disadvantage of increasing event size +accordingly. + +\section{CODES/ROSS: general tips and tricks} + +\subsection{Initializing the model} + +There are two conceptual steps to initializing a CODES model - LP registration +in ROSS and configuration via consulting the CODES configuration file. In older +versions of models we wrote, these two steps were together. However, it is +highly suggested to separate these two steps into different functions, with the +registration occurring before the call to \texttt{codes\_mapping\_setup}, and +the configuration occurring after the call. This allows the codes-mapping API +to be used at configuration time, which is often useful when LPs need to know +things like LP counts and doing these in the ROSS LP init function would lead +to unnecessary computation. It is especially useful for configuration schemes +that require knowledge of LP annotations. + +\subsection{LP-IO usage} + +LP-IO is a simple and useful optimistic-aware IO utility for optimistic +simulations. Based on our usage, we have the following recommendations for +effective usage of it: +\begin{enumerate} + \item Use the command-line to configure turning IO on and off in its + entirety, and to specify where the output should be placed. Suggested + options: + \begin{enumerate} + \item \texttt{--lp-io-dir=DIR} -- use DIR as the output directory - + absence of the option indicates no LP-IO output. + \item \texttt{--lp-io-use-suffix=DUMMY} -- add the PID of the root + rank to the directory name to avoid clashes between + multiple runs. If not specified, then the DIR option + will be exactly used, possibly leading to an error/exit. The + dummy argument is due to a ROSS limitation of not allowing + ``flag''-style options (options with no arguments). + \end{enumerate} + \item Use LP-specific options in the CODES configuration file to drive + specific options for output within the LP. +\end{enumerate} + +\subsection{Avoiding event timestamp ties} + +Event timestamp ties in ROSS occur when two or more events have the same +timestamp. These have a variety of unintended consequences, most significant of +which is hampering both reproducability and determinism in simulations. To +avoid this, use codes\_local\_latency for events with small or zero time deltas +to add some random noise. codes\_local\_latency must be reversed, so use +codes\_local\_latency\_reverse in reverse event handlers. + +One example of this usage is exchanging events between LPs without really +consuming significant time (for example, to transfer information from a server +to its locally attached network card). It is tempting to use a timestamp of 0, +but this would cause timestamp ties in ROSS. Use of codes\_local\_latency for +timing of local event transitions in this case can be thought of as bus +overhead or context switch overhead. + +\subsection{Organizing event structures} + +Since a single event structure contains data for all of the different types of +events processed by the LP, use a type enum + unions (otherwise known as a +``tagged struct'') as an organizational strategy. Keeps the event size down and +makes it a little clearer what variables are used by which event types. + +\subsection{Validating across simulation modes} + +During development, you should do test runs with serial, parallel conservative, +and parallel optimistic runs to make sure that you get consistent results. +These modes stress different aspects of the model. + +\subsection{How to complete a simulation} + +Most core ROSS examples are design to intentionally hit +the end timestamp for the simulation (i.e. they are modeling a continuous, +steady state system). This isn't necessarily true for other models. Quite +simply, set g\_tw\_ts\_end to an arbitrary large number when running simulations +that have a well-defined end-point in terms of events processed. + +Within the LP finalize function, do not call tw\_now. The time returned may not +be consistent in the case of an optimistic simulation. + +\section{Best practices quick reference} + +NOTE: these may be integrated with the remaining notes or used as a summary of +section(s). + +\subsection{ROSS simulation development} + +\begin{enumerate} + + \item prefer fine-grained, simple LPs to coarse-grained, complex LPs + \begin{enumerate} + \item can simplify both LP state and reverse computation implementation + \item ROSS is very good at event processing, likely small difference in + performance + \end{enumerate} + + \item consider separating single-source generation of concurrent events with + "feedback" events or "continue" events to self + \begin{enumerate} + \item generating multiple concurrent events makes rollback more difficult + \end{enumerate} + + \item use dummy events to work around "event-less" advancement of simulation time + + \item add a small amount of time "noise" to events to prevent ties + + \item prefer more and smaller events to fewer and larger events + \begin{enumerate} + \item simplifies individual event processing + \item ROSS uses bounded event structure size in communication, so + smaller bound $\rightarrow$ less communication overhead + \end{enumerate} + + \item prefer placing state in event structure to LP state structure + \begin{enumerate} + \item simplifies reverse computation -- less persistent state + \item NOTE: tradeoff with previous point - consider efficiency vs.\ + complexity + \end{enumerate} + + \item try to implement event processing with only LP-local information + \begin{enumerate} + \item reverse computation with collective knowledge is difficult + \end{enumerate} + + \item separate ROSS registration from LP configuration functionality + + \item use self-suspend liberally + \item stash data from destructive operations (floating point computations, + freed data, re-assigned variables) in the event structure causing the + destruction + \item prefer static memory in LP states to dynamic memory + +\end{enumerate} + +\section{TODO} + +\begin{itemize} + \item add code examples? + \item put a pdf or latex2html version of this document on the codes web page + when it's ready +\end{itemize} + +\begin{comment} ==== SCRATCH MATERIAL ==== +\begin{figure} +\begin{lstlisting}[caption=Example code snippet., label=snippet-example] +for (i=0; i +#include +#include + +#include "codes/lp-io.h" +#include "codes/codes.h" +#include "codes/codes_mapping.h" +#include "codes/configuration.h" +#include "codes/model-net.h" +#include "codes/lp-type-lookup.h" +#include "codes/local-storage-model.h" + +static int num_reqs = 0;/* number of requests sent by each server (read from config) */ +static int payload_sz = 0; /* size of simulated data payload, bytes (read from config) */ + +/* model-net ID, can be either simple-net, dragonfly or torus (more may be + * added) */ +static int net_id = 0; +static int num_servers = 0; +static int offset = 2; + +/* expected LP group name in configure files for this program */ +static char *group_name = "SERVERS"; +/* expected parameter group name for rounds of communication */ +static char *param_group_nm = "server_pings"; +static char *num_reqs_key = "num_reqs"; +static char *payload_sz_key = "payload_sz"; + +typedef struct svr_msg svr_msg; +typedef struct svr_state svr_state; + +/* types of events that will constitute server activities */ +enum svr_event +{ + KICKOFF, /* initial event */ + REQ, /* request event */ + ACK, /* ack event */ + LOCAL /* local event */ +}; + +/* this struct serves as the ***persistent*** state of the LP representing the + * server in question. This struct is setup when the LP initialization function + * ptr is called */ +struct svr_state +{ + int msg_sent_count; /* requests sent */ + int msg_recvd_count; /* requests recvd */ + int local_recvd_count; /* number of local messages received */ + tw_stime start_ts; /* time that we started sending requests */ + tw_stime end_ts; /* time that last request finished */ +}; + +/* this struct serves as the ***temporary*** event data, which can be thought + * of as a message between two LPs. */ +struct svr_msg +{ + enum svr_event svr_event_type; + tw_lpid src; /* source of this request or ack */ + + int incremented_flag; /* helper for reverse computation */ +}; + +/* ROSS expects four functions per LP: + * - an LP initialization function, called for each LP + * - an event processing function + * - a *reverse* event processing function (rollback), and + * - a finalization/cleanup function when the simulation ends + */ +static void svr_init( + svr_state * ns, + tw_lp * lp); +static void svr_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp); +static void svr_rev_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp); +static void svr_finalize( + svr_state * ns, + tw_lp * lp); + +/* set up the function pointers for ROSS, as well as the size of the LP state + * structure (NOTE: ROSS is in charge of event and state (de-)allocation) */ +tw_lptype svr_lp = { + (init_f) svr_init, + (pre_run_f) NULL, + (event_f) svr_event, + (revent_f) svr_rev_event, + (final_f) svr_finalize, + (map_f) codes_mapping, + sizeof(svr_state), +}; + +extern const tw_lptype* svr_get_lp_type(); +static void svr_add_lp_type(); +static tw_stime ns_to_s(tw_stime ns); +static tw_stime s_to_ns(tw_stime ns); + +/* as we only have a single event processing entry point and multiple event + * types, for clarity we define "handlers" for each (reverse) event type */ +static void handle_kickoff_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp); +static void handle_ack_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp); +static void handle_req_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp); +static void handle_local_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp); +static void handle_local_rev_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp); +static void handle_kickoff_rev_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp); +static void handle_ack_rev_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp); +static void handle_req_rev_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp); + +/* for this simulation, each server contacts its neighboring server in an id. + * this function shows how to use the codes_mapping API to calculate IDs when + * having to contend with multiple LP types and counts. Note that in this simple + * example codes_mapping is overkill. */ +static tw_lpid get_next_server(tw_lpid sender_id); + +/* arguments to be handled by ROSS - strings passed in are expected to be + * pre-allocated */ +static char conf_file_name[256] = {0}; +/* this struct contains default parameters used by ROSS, as well as + * user-specific arguments to be handled by the ROSS config sys. Pass it in + * prior to calling tw_init */ +const tw_optdef app_opt [] = +{ + TWOPT_GROUP("Model net test case" ), + TWOPT_CHAR("codes-config", conf_file_name, "name of codes configuration file"), + TWOPT_END() +}; + +int main( + int argc, + char **argv) +{ + int nprocs; + int rank; + int num_nets, *net_ids; + + /* TODO: explain why we need this (ROSS has cutoff??) */ + g_tw_ts_end = s_to_ns(60*60*24*365); /* one year, in nsecs */ + + /* ROSS initialization function calls */ + tw_opt_add(app_opt); /* add user-defined args */ + /* initialize ROSS and parse args. NOTE: tw_init calls MPI_Init */ + tw_init(&argc, &argv); + + if (!conf_file_name[0]) + { + fprintf(stderr, "Expected \"codes-config\" option, please see --help.\n"); + MPI_Finalize(); + return 1; + } + + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &nprocs); + + /* loading the config file into the codes-mapping utility, giving us the + * parsed config object in return. + * "config" is a global var defined by codes-mapping */ + if (configuration_load(conf_file_name, MPI_COMM_WORLD, &config)){ + fprintf(stderr, "Error loading config file %s.\n", conf_file_name); + MPI_Finalize(); + return 1; + } + + /* register model-net LPs with ROSS */ + model_net_register(); + + /* register the server LP type with ROSS */ + svr_add_lp_type(); + + /* Setup takes the global config object, the registered LPs, and + * generates/places the LPs as specified in the configuration file. + * This should only be called after ALL LP types have been registered in + * codes */ + codes_mapping_setup(); + + /* Setup the model-net parameters specified in the global config object, + * returned are the identifier(s) for the network type. In this example, we + * only expect one*/ + net_ids = model_net_configure(&num_nets); + assert(num_nets==1); + net_id = *net_ids; + free(net_ids); + /* in this example, we are using simplenet, which simulates point to point + * communication between any two entities (other networks are trickier to + * setup). Hence: */ + if(net_id != SIMPLENET) + { + printf("\n The test works with simple-net configuration only! "); + MPI_Finalize(); + return 0; + } + + /* calculate the number of servers in this simulation, + * ignoring annotations */ + num_servers = codes_mapping_get_lp_count(group_name, 0, "server", NULL, 1); + + /* for this example, we read from a separate configuration group for + * server message parameters. Since they are constant for all LPs, + * go ahead and read them prior to running */ + configuration_get_value_int(&config, param_group_nm, num_reqs_key, NULL, &num_reqs); + configuration_get_value_int(&config, param_group_nm, payload_sz_key, NULL, &payload_sz); + + /* begin simulation */ + tw_run(); + + /* model-net has the capability of outputting network transmission stats */ + model_net_report_stats(net_id); + + tw_end(); + return 0; +} + +const tw_lptype* svr_get_lp_type() +{ + return(&svr_lp); +} + +static void svr_add_lp_type() +{ + /* lp_type_register should be called exactly once per process per + * LP type */ + lp_type_register("server", svr_get_lp_type()); +} + +static void svr_init( + svr_state * ns, + tw_lp * lp) +{ + tw_event *e; + svr_msg *m; + tw_stime kickoff_time; + + memset(ns, 0, sizeof(*ns)); + + /* each server sends a dummy event to itself that will kick off the real + * simulation + */ + + /* skew each kickoff event slightly to help avoid event ties later on */ + kickoff_time = g_tw_lookahead + tw_rand_unif(lp->rng); + + /* first create the event (time arg is an offset, not absolute time) */ + e = codes_event_new(lp->gid, kickoff_time, lp); + /* after event is created, grab the allocated message and set msg-specific + * data */ + m = tw_event_data(e); + m->svr_event_type = KICKOFF; + /* event is ready to be processed, send it off */ + tw_event_send(e); + + return; +} + +/* event processing entry point + * - simply forward the message to the appropriate handler */ +static void svr_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp) +{ + switch (m->svr_event_type) + { + case REQ: + handle_req_event(ns, b, m, lp); + break; + case ACK: + handle_ack_event(ns, b, m, lp); + break; + case KICKOFF: + handle_kickoff_event(ns, b, m, lp); + break; + case LOCAL: + handle_local_event(ns, b, m, lp); + break; + default: + printf("\n Invalid message type %d ", m->svr_event_type); + assert(0); + break; + } +} + +/* reverse event processing entry point + * - simply forward the message to the appropriate handler */ +static void svr_rev_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp) +{ + switch (m->svr_event_type) + { + case REQ: + handle_req_rev_event(ns, b, m, lp); + break; + case ACK: + handle_ack_rev_event(ns, b, m, lp); + break; + case KICKOFF: + handle_kickoff_rev_event(ns, b, m, lp); + break; + case LOCAL: + handle_local_rev_event(ns, b, m, lp); + break; + default: + assert(0); + break; + } + + return; +} + +/* once the simulation is over, do some output */ +static void svr_finalize( + svr_state * ns, + tw_lp * lp) +{ + printf("server %llu recvd %d bytes in %lf seconds, %lf MiB/s sent_count %d recvd_count %d local_count %d \n", + (unsigned long long)(lp->gid/2), + payload_sz*ns->msg_recvd_count, + ns_to_s(ns->end_ts-ns->start_ts), + ((double)(payload_sz*num_reqs)/(double)(1024*1024)/ns_to_s(ns->end_ts-ns->start_ts)), + ns->msg_sent_count, + ns->msg_recvd_count, + ns->local_recvd_count); + return; +} + +/* convert ns to seconds */ +static tw_stime ns_to_s(tw_stime ns) +{ + return(ns / (1000.0 * 1000.0 * 1000.0)); +} + +/* convert seconds to ns */ +static tw_stime s_to_ns(tw_stime ns) +{ + return(ns * (1000.0 * 1000.0 * 1000.0)); +} + +/* see declaration for more general info */ +tw_lpid get_next_server(tw_lpid sender_id) +{ + tw_lpid rtn_id; + /* first, get callers LP and group info from codes-mapping. Caching this + * info in the LP struct isn't a bad idea for preventing a huge number of + * lookups */ + char grp_name[MAX_NAME_LENGTH], lp_type_name[MAX_NAME_LENGTH], + annotation[MAX_NAME_LENGTH]; + int lp_type_id, grp_id, grp_rep_id, offset, num_reps; + int dest_rep_id; + codes_mapping_get_lp_info(sender_id, grp_name, &grp_id, lp_type_name, + &lp_type_id, annotation, &grp_rep_id, &offset); + /* in this example, we assume that, for our group of servers, each + * "repetition" consists of a single server/NIC pair. Hence, we grab the + * server ID for the next repetition, looping around if necessary */ + num_reps = codes_mapping_get_group_reps(grp_name); + dest_rep_id = (grp_rep_id+1) % num_reps; + /* finally, get the server (exactly 1 server per rep -> offset w/in rep = 0 */ + codes_mapping_get_lp_id(grp_name, lp_type_name, NULL, 1, dest_rep_id, + 0, &rtn_id); + return rtn_id; +} + +/* handle initial event */ +static void handle_kickoff_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp) +{ + int dest_id; + int use_brute_force_map = 0; + /* normally, when using ROSS, events are allocated as a result of the event + * creation process. However, since we are now asking model-net to + * communicate with an entity on our behalf, we need to generate both the + * message to the recipient and an optional callback message + * - thankfully, memory need not persist past the model_net_event call - it + * copies the messages */ + svr_msg m_local; + svr_msg m_remote; + + m_local.svr_event_type = LOCAL; + m_local.src = lp->gid; + m_remote.svr_event_type = REQ; + m_remote.src = lp->gid; + + /* record when transfers started on this server */ + ns->start_ts = tw_now(lp); + + /* each server sends a request to the next highest server + * In this simulation, LP determination is simple: LPs are assigned + * round robin as in serv_1, net_1, serv_2, net_2, etc. + * However, that may not always be the case, so we also show a more + * complicated way to map through codes_mapping */ + if (use_brute_force_map) + dest_id = (lp->gid + offset)%(num_servers*2); + else + { + dest_id = get_next_server(lp->gid); + } + + /* model-net needs to know about (1) higher-level destination LP which is a neighboring server in this case + * (2) struct and size of remote message and (3) struct and size of local message (a local message can be null) */ + model_net_event(net_id, "test", dest_id, payload_sz, 0.0, sizeof(svr_msg), + (const void*)&m_remote, sizeof(svr_msg), (const void*)&m_local, lp); + ns->msg_sent_count++; +} + +/* at the moment, no need for local callbacks from model-net, so we maintain a + * count for debugging purposes */ +static void handle_local_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp) +{ + ns->local_recvd_count++; +} + +/* handle recving ack + * for this simulation, we repeatedly ping the destination server until num_reqs + * of size payload_sz have been satisfied - we begin the next req when we + * receive an ACK from the destination server */ +static void handle_ack_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp) +{ + /* the ACK actually doesn't come from the NIC on the other server - + * model-net "hides" the NIC LP from us so we only see the original + * destination server */ + + /* safety check that this request got to the right server, both with our + * brute-force lp calculation and our more generic codes-mapping + * calculation */ + assert(m->src == (lp->gid + offset)%(num_servers*2) && + m->src == get_next_server(lp->gid)); + + if(ns->msg_sent_count < num_reqs) + { + /* again, allocate our own msgs so model-net can transmit on our behalf */ + svr_msg m_local; + svr_msg m_remote; + + m_local.svr_event_type = LOCAL; + m_local.src = lp->gid; + m_remote.svr_event_type = REQ; + m_remote.src = lp->gid; + + /* send another request */ + model_net_event(net_id, "test", m->src, payload_sz, 0.0, sizeof(svr_msg), + (const void*)&m_remote, sizeof(svr_msg), (const void*)&m_local, lp); + ns->msg_sent_count++; + m->incremented_flag = 1; + + } + else + { + /* threshold count reached, stop sending messages */ + m->incremented_flag = 0; + ns->end_ts = tw_now(lp); + } + return; +} + +/* handle receiving request */ +static void handle_req_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp) +{ + svr_msg m_local; + svr_msg m_remote; + + m_local.svr_event_type = LOCAL; + m_local.src = lp->gid; + m_remote.svr_event_type = ACK; + m_remote.src = lp->gid; + + /* safety check that this request got to the right server */ + + assert(lp->gid == (m->src + offset)%(num_servers*2) && + lp->gid == get_next_server(m->src)); + ns->msg_recvd_count++; + + /* send ack back */ + /* simulated payload of 1 MiB */ + /* also trigger a local event for completion of payload msg */ + /* remote host will get an ack event */ + + model_net_event(net_id, "test", m->src, payload_sz, 0.0, sizeof(svr_msg), + (const void*)&m_remote, sizeof(svr_msg), (const void*)&m_local, lp); + return; +} + +/* for us, reverse events are very easy, the only LP state that needs to be + * rolled back are the counts. + * for more complex simulations, this will not be the case (e.g., state + * containing queues) */ + +static void handle_local_rev_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp) +{ + ns->local_recvd_count--; +} +/* reverse handler for req event */ +static void handle_req_rev_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp) +{ + ns->msg_recvd_count--; + /* model-net has its own reverse computation support */ + model_net_event_rc(net_id, lp, payload_sz); + + return; +} + + +/* reverse handler for kickoff */ +static void handle_kickoff_rev_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp) +{ + ns->msg_sent_count--; + model_net_event_rc(net_id, lp, payload_sz); + + return; +} + +/* reverse handler for ack*/ +static void handle_ack_rev_event( + svr_state * ns, + tw_bf * b, + svr_msg * m, + tw_lp * lp) +{ + if(m->incremented_flag) + { + model_net_event_rc(net_id, lp, payload_sz); + ns->msg_sent_count--; + } + return; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ft=c ts=8 sts=4 sw=4 expandtab + */ diff --git a/doc/example/example.conf b/doc/example/example.conf new file mode 100644 index 0000000000000000000000000000000000000000..1138ed7e3738007783f7d0aa3bff98f8d074b96b --- /dev/null +++ b/doc/example/example.conf @@ -0,0 +1,56 @@ +# the LPGROUPS set is required by all simulations using codes. Multiple groups +# can be entered (only one is here for our example), each consisting of a set +# of application- and codes-specific key-value pairs. +LPGROUPS +{ + # in our simulation, we simply have a set of servers, each with + # point-to-point access to each other + SERVERS + { + # required: number of times to repeat the following key-value pairs + repetitions="16"; + # application-specific: parsed in main + server="1"; + # model-net-specific field defining the network backend. In this example, + # each server has one NIC, and each server are point-to-point connected + modelnet_simplenet="1"; + } +} +# required by CODES: miscellaneous parameters used in the simulation that +# don't fit in group definition. +PARAMS +{ + # ROSS-specific parmeters: + # - message_size: ROSS expects you to upper bound your event message size. + # Going over this size will crash or otherwise destroy your + # simulation. + message_size="256"; + # - pe_mem_factor: this is a multiplier to the event memory allocation that + # ROSS does up front (multiplier is per-PE). Increase this + # (or change the associated mem_factor variable in + # codes-base) if you have a (very) large event population. + pe_mem_factor="512"; + # model-net-specific parameters: + # - individual packet sizes for network operations + # (each "packet" is represented by an event) + # - independent of underlying network being used + packet_size="512"; + # - order that network types will be presented to the user in + # model_net_set_params. In this example, we're only using a single + # network + modelnet_order=("simplenet"); + # - message scheduling algorithm (on a per-packet basis) + modelnet_scheduler="fcfs"; # first come first serve + # modelnet_scheduler="round-robin"; # round-robin + # - model-specific parameters + net_startup_ns="1.5"; + net_bw_mbps="20000"; +} + +# custom parameter sets can also be added - this one is used to define the +# rounds of communication the servers will undergo +server_pings +{ + num_reqs="5"; + payload_sz="4096"; +} diff --git a/doc/example_heterogeneous/Makefile b/doc/example_heterogeneous/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..b152aa5414306e164a5301c77bae8dae38cef671 --- /dev/null +++ b/doc/example_heterogeneous/Makefile @@ -0,0 +1,21 @@ +ifndef CODESBASE +$(error CODESBASE is undefined, see README.txt) +endif +ifndef CODESNET +$(error CODESNET is undefined, see README.txt) +endif +ifndef ROSS +$(error ROSS is undefined, see README.txt) +endif + +PKG_PATH = $(ROSS)/lib/pkgconfig:$(CODESBASE)/lib/pkgconfig:$(CODESNET)/lib/pkgconfig + +override CPPFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_PATH) pkg-config --cflags codes-net codes-base ross) +LDFLAGS += $(shell PKG_CONFIG_PATH=$(PKG_PATH) pkg-config --libs-only-L ross codes-net codes-base ross) +LDLIBS = $(shell PKG_CONFIG_PATH=$(PKG_PATH) pkg-config --libs-only-l ross codes-net codes-base ross) +CC = mpicc + +example: example.c + +clean: + rm -f example diff --git a/doc/example_heterogeneous/README b/doc/example_heterogeneous/README new file mode 100644 index 0000000000000000000000000000000000000000..754e9344c6825a0d5463b8c169eed63383b0bfbe --- /dev/null +++ b/doc/example_heterogeneous/README @@ -0,0 +1,14 @@ +This example program shows some features enabled by the new annotation-based +configuration and mapping APIs in codes-base, as well as support for them in +codes-net. The example does not exhaustively show all new features added - for +more details, see configuration.h, codes-mapping.h, and model-net.h in +codes-net. + +Specifically, some features shown are: +* Use of annotated configuration to initialize three separate network models. + Note that they are all the same network model, just with different + parameterizations. This includes both the configuration file itself as well as + interaction in the code between components with different annotations. +* Addressing at various levels in both LP type-specific namespaces and + model-net namespaces (network id, annotation tuples). +* The updated registration/configuration sequence in main. diff --git a/doc/example_heterogeneous/example.c b/doc/example_heterogeneous/example.c new file mode 100644 index 0000000000000000000000000000000000000000..9b7fab1fe97603a0deb713909864522459bd4187 --- /dev/null +++ b/doc/example_heterogeneous/example.c @@ -0,0 +1,483 @@ +/* + * Copyright (C) 2014 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include "codes/codes_mapping.h" +#include "codes/lp-type-lookup.h" +#include "codes/jenkins-hash.h" +#include "codes/codes.h" +#include "codes/lp-msg.h" +#include +#include + +/**** BEGIN SIMULATION DATA STRUCTURES ****/ + +/* 'magic' numbers used as sanity check on events */ +static int node_magic; +static int forwarder_magic; + +/* counts of the various types of nodes in the example system */ +static int num_foo_nodes, num_bar_nodes; +static int num_foo_forwarders, num_bar_forwarders; + +/* pings to perform (provided by config file) */ +static int num_pings; +static uint64_t payload_sz; + +/* network type for the various clusters */ +static int net_id_foo, net_id_bar, net_id_forwarding; + +/* event types */ +enum node_event +{ + NODE_KICKOFF = 123, + NODE_RECV_PING, + NODE_RECV_PONG, +}; + +typedef struct node_state_s { + int is_in_foo; // whether we're in foo's or bar's cluster + int id_clust; // my index within the cluster + int num_processed; // number of requests processed +} node_state; + +typedef struct node_msg_s { + msg_header h; + int id_clust_src; +} node_msg; + +enum forwarder_event +{ + FORWARDER_FWD = 234, + FORWARDER_RECV, +}; + +typedef struct forwarder_state_s { + int id; // index w.r.t. forwarders in my group + int is_in_foo; + int fwd_node_count; + int fwd_forwarder_count; +} forwarder_state; + +typedef struct forwarder_msg_s { + msg_header h; + int src_node_clust_id; + int dest_node_clust_id; + enum node_event node_event_type; +} forwarder_msg; + +/**** END SIMULATION DATA STRUCTURES ****/ + +/**** BEGIN IMPLEMENTATIONS ****/ + +void node_lp_init( + node_state * ns, + tw_lp * lp){ + ns->num_processed = 0; + // nodes are addressed in their logical id space (0...num_foo_nodes-1 and + // 0...num_bar_nodes-1, respectively). LPs are computed upon use with + // model-net, other events + ns->id_clust = codes_mapping_get_lp_relative_id(lp->gid, 1, 0); + int id_all = codes_mapping_get_lp_relative_id(lp->gid, 0, 0); + // track which cluster we're in + ns->is_in_foo = (id_all < num_foo_nodes); + + // send a self kickoff event + tw_event *e = codes_event_new(lp->gid, codes_local_latency(lp), lp); + node_msg *m = tw_event_data(e); + msg_set_header(node_magic, NODE_KICKOFF, lp->gid, &m->h); + tw_event_send(e); +} + +void node_finalize( + node_state * ns, + tw_lp * lp){ + // do some error checking - here, we ensure we got the expected number of + // messages + int mult; + if (ns->is_in_foo){ + mult = 1; + } + else{ + mult = (num_foo_nodes / num_bar_nodes) + + ((num_foo_nodes % num_bar_nodes) > ns->id_clust); + } + if (ns->num_processed != num_pings*mult){ + fprintf(stderr, + "%s node %d, lp %lu: processed %d (expected %d)\n", + ns->is_in_foo ? "foo" : "bar", ns->id_clust, lp->gid, + ns->num_processed, num_pings*mult); + } +} + +/* event type handlers */ +void handle_node_next( + node_state * ns, + node_msg * m, + tw_lp * lp){ + // we must be in cluster foo for this function + assert(ns->is_in_foo); + + // generate a message to send to the forwarder + forwarder_msg m_fwd; + msg_set_header(forwarder_magic, FORWARDER_FWD, lp->gid, &m_fwd.h); + + m_fwd.src_node_clust_id = ns->id_clust; + // compute the destination in cluster bar to ping based on a simple modulo + // of the logical indexes + m_fwd.dest_node_clust_id = ns->id_clust % num_bar_nodes; + m_fwd.node_event_type = NODE_RECV_PING; + + // compute the dest forwarder index, again using a simple modulo + int dest_fwd_id = ns->id_clust % num_foo_forwarders; + + // as the relative forwarder IDs are with respect to groups, the group + // name must be used + tw_lpid dest_fwd_lpid = codes_mapping_get_lpid_from_relative(dest_fwd_id, + "FOO_FORWARDERS", "forwarder", NULL, 0); + + // as cluster nodes have only one network type (+ annotation), no need to + // use annotation-specific messaging + model_net_event_annotated(net_id_foo, "foo", "ping", dest_fwd_lpid, + payload_sz, 0.0, sizeof(m_fwd), &m_fwd, 0, NULL, lp); +} + +void handle_node_recv_ping( + node_state * ns, + node_msg * m, + tw_lp * lp){ + // we must be in cluster bar to receive pings + assert(!ns->is_in_foo); + + // check that we received the msg from the expected source + assert(m->id_clust_src % num_bar_nodes == ns->id_clust); + + // setup the response message through the forwarder + forwarder_msg m_fwd; + msg_set_header(forwarder_magic, FORWARDER_FWD, lp->gid, &m_fwd.h); + m_fwd.src_node_clust_id = ns->id_clust; + m_fwd.dest_node_clust_id = m->id_clust_src; + m_fwd.node_event_type = NODE_RECV_PONG; + + // compute the dest forwarder index, again using a simple modulus + int dest_fwd_id = ns->id_clust % num_bar_forwarders; + + // as the relative forwarder IDs are with respect to groups, the group + // name must be used + tw_lpid dest_fwd_lpid = codes_mapping_get_lpid_from_relative(dest_fwd_id, + "BAR_FORWARDERS", "forwarder", NULL, 0); + + model_net_event_annotated(net_id_bar, "bar", "pong", dest_fwd_lpid, + payload_sz, 0.0, sizeof(m_fwd), &m_fwd, 0, NULL, lp); + + ns->num_processed++; +} + +void handle_node_recv_pong( + node_state * ns, + node_msg * m, + tw_lp * lp){ + // we must be in cluster foo + assert(ns->id_clust < num_foo_nodes); + + // simply process the next message + ns->num_processed++; + if (ns->num_processed < num_pings){ + handle_node_next(ns, m, lp); + } +} + +void node_event_handler( + node_state * ns, + tw_bf * b, + node_msg * m, + tw_lp * lp){ + assert(m->h.magic == node_magic); + + switch (m->h.event_type){ + case NODE_KICKOFF: + // nodes from foo ping to nodes in bar + if (ns->is_in_foo){ + handle_node_next(ns, m, lp); + } + break; + case NODE_RECV_PING: + handle_node_recv_ping(ns, m, lp); + break; + case NODE_RECV_PONG: + handle_node_recv_pong(ns, m, lp); + break; + /* ... */ + default: + tw_error(TW_LOC, "node event type not known"); + } +} + +/* ROSS function pointer table for this LP */ +static tw_lptype node_lp = { + (init_f) node_lp_init, + (pre_run_f) NULL, + (event_f) node_event_handler, + (revent_f) NULL, + (final_f) node_finalize, + (map_f) codes_mapping, + sizeof(node_state), +}; + +void node_register(){ + uint32_t h1=0, h2=0; + + bj_hashlittle2("node", strlen("node"), &h1, &h2); + node_magic = h1+h2; + + lp_type_register("node", &node_lp); +} + + +/*** Forwarder LP ***/ + +void forwarder_lp_init( + forwarder_state * ns, + tw_lp * lp){ + // like nodes, forwarders in this example are addressed logically + ns->id = codes_mapping_get_lp_relative_id(lp->gid, 1, 0); + int id_all = codes_mapping_get_lp_relative_id(lp->gid, 0, 0); + ns->is_in_foo = (id_all < num_foo_forwarders); +} + +void forwarder_finalize( + forwarder_state * ns, + tw_lp * lp){ + // nothing to see here +} + +void handle_forwarder_fwd( + forwarder_state * ns, + forwarder_msg * m, + tw_lp * lp){ + // compute the forwarder lpid to forward to + int mod; + const char * dest_group; + char * category; + if (ns->is_in_foo){ + mod = num_bar_forwarders; + dest_group = "BAR_FORWARDERS"; + category = "ping"; + } + else{ + mod = num_foo_forwarders; + dest_group = "FOO_FORWARDERS"; + category = "pong"; + } + + // compute the ROSS id corresponding to the dest forwarder + tw_lpid dest_lpid = codes_mapping_get_lpid_from_relative( + ns->id % mod, dest_group, "forwarder", NULL, 0); + + forwarder_msg m_fwd = *m; + msg_set_header(forwarder_magic, FORWARDER_RECV, lp->gid, &m_fwd.h); + + // here, we need to use the unannotated forwarding network, so we + // use the annotation version of model_net_event + model_net_event_annotated(net_id_forwarding, NULL, category, dest_lpid, + payload_sz, 0.0, sizeof(m_fwd), &m_fwd, 0, NULL, lp); + + ns->fwd_node_count++; +} + +void handle_forwarder_recv( + forwarder_state * ns, + forwarder_msg * m, + tw_lp * lp) { + // compute the node to relay the message to + const char * dest_group; + const char * annotation; + char * category; + int net_id; + if (ns->is_in_foo){ + dest_group = "FOO_CLUSTER"; + annotation = "foo"; + category = "pong"; + net_id = net_id_foo; + } + else{ + dest_group = "BAR_CLUSTER"; + annotation = "bar"; + category = "ping"; + net_id = net_id_bar; + } + + tw_lpid dest_lpid = codes_mapping_get_lpid_from_relative( + m->dest_node_clust_id, dest_group, "node", + NULL, 0); + + node_msg m_node; + msg_set_header(node_magic, m->node_event_type, lp->gid, &m_node.h); + m_node.id_clust_src = m->src_node_clust_id; + + // here, we need to use the foo or bar cluster's internal network, so we use + // the annotated version of model_net_event + model_net_event_annotated(net_id, annotation, category, dest_lpid, + payload_sz, 0.0, sizeof(m_node), &m_node, 0, NULL, lp); + + ns->fwd_forwarder_count++; +} + +void forwarder_event_handler( + forwarder_state * ns, + tw_bf * b, + forwarder_msg * m, + tw_lp * lp){ + assert(m->h.magic == forwarder_magic); + + switch(m->h.event_type){ + case FORWARDER_FWD: + handle_forwarder_fwd(ns, m, lp); + break; + case FORWARDER_RECV: + handle_forwarder_recv(ns, m, lp); + break; + default: + tw_error(TW_LOC, "unknown forwarder event type"); + } +} + +static tw_lptype forwarder_lp = { + (init_f) forwarder_lp_init, + (pre_run_f) NULL, + (event_f) forwarder_event_handler, + (revent_f) NULL, + (final_f) forwarder_finalize, + (map_f) codes_mapping, + sizeof(forwarder_state), +}; + +void forwarder_register(){ + uint32_t h1=0, h2=0; + + bj_hashlittle2("forwarder", strlen("forwarder"), &h1, &h2); + forwarder_magic = h1+h2; + + lp_type_register("forwarder", &forwarder_lp); +} + +/**** END IMPLEMENTATIONS ****/ + +/* arguments to be handled by ROSS - strings passed in are expected to be + * pre-allocated */ +static char conf_file_name[256] = {0}; +/* this struct contains default parameters used by ROSS, as well as + * user-specific arguments to be handled by the ROSS config sys. Pass it in + * prior to calling tw_init */ +const tw_optdef app_opt [] = +{ + TWOPT_GROUP("Model net test case" ), + TWOPT_CHAR("codes-config", conf_file_name, "name of codes configuration file"), + TWOPT_END() +}; + +static tw_stime s_to_ns(tw_stime ns) +{ + return(ns * (1000.0 * 1000.0 * 1000.0)); +} + +int main(int argc, char *argv[]) +{ + g_tw_ts_end = s_to_ns(60*60*24*365); /* one year, in nsecs */ + + /* ROSS initialization function calls */ + tw_opt_add(app_opt); /* add user-defined args */ + /* initialize ROSS and parse args. NOTE: tw_init calls MPI_Init */ + tw_init(&argc, &argv); + + if (!conf_file_name[0]) { + tw_error(TW_LOC, + "Expected \"codes-config\" option, please see --help.\n"); + return 1; + } + + /* loading the config file into the codes-mapping utility, giving us the + * parsed config object in return. + * "config" is a global var defined by codes-mapping */ + if (configuration_load(conf_file_name, MPI_COMM_WORLD, &config)){ + tw_error(TW_LOC, "Error loading config file %s.\n", conf_file_name); + return 1; + } + + /* register model-net LPs with ROSS */ + model_net_register(); + + /* register the user LPs */ + node_register(); + forwarder_register(); + + /* setup the LPs and codes_mapping structures */ + codes_mapping_setup(); + + /* setup the globals */ + int rc = configuration_get_value_int(&config, "run_params", "num_reqs", NULL, + &num_pings); + if (rc != 0) + tw_error(TW_LOC, "unable to read run_params:num_reqs"); + int payload_sz_d; + rc = configuration_get_value_int(&config, "run_params", "payload_sz", NULL, + &payload_sz_d); + if (rc != 0) + tw_error(TW_LOC, "unable to read run_params:payload_sz"); + payload_sz = (uint64_t) payload_sz_d; + + /* get the counts for the foo and bar clusters */ + num_foo_nodes = codes_mapping_get_lp_count("FOO_CLUSTER", 0, "node", + NULL, 1); + num_bar_nodes = codes_mapping_get_lp_count("BAR_CLUSTER", 0, "node", + NULL, 1); + num_foo_forwarders = codes_mapping_get_lp_count("FOO_FORWARDERS", 0, + "forwarder", NULL, 1); + num_bar_forwarders = codes_mapping_get_lp_count("BAR_FORWARDERS", 0, + "forwarder", NULL, 1); + + + /* Setup the model-net parameters specified in the global config object, + * returned are the identifier(s) for the network type. + * 1 ID -> all the same modelnet model + * 2 IDs -> clusters are the first id, forwarding network the second + * 3 IDs -> cluster foo is the first, bar is the second, + * forwarding network the third */ + int num_nets; + int *net_ids = model_net_configure(&num_nets); + assert(num_nets <= 3); + if (num_nets == 1) { + net_id_foo = net_ids[0]; + net_id_bar = net_ids[0]; + net_id_forwarding = net_ids[0]; + } + else if (num_nets == 2) { + net_id_foo = net_ids[0]; + net_id_bar = net_ids[0]; + net_id_forwarding = net_ids[1]; + } + else { + net_id_foo = net_ids[0]; + net_id_bar = net_ids[1]; + net_id_forwarding = net_ids[2]; + } + free(net_ids); + + /* begin simulation */ + tw_run(); + + tw_end(); + + return 0; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ft=c ts=8 sts=4 sw=4 expandtab + */ diff --git a/doc/example_heterogeneous/example.conf b/doc/example_heterogeneous/example.conf new file mode 100644 index 0000000000000000000000000000000000000000..7f00fe2915c293c4ae62c4da14ca4dbe0ee7b368 --- /dev/null +++ b/doc/example_heterogeneous/example.conf @@ -0,0 +1,57 @@ +LPGROUPS { + ## cluster foo + FOO_CLUSTER { + repetitions="12"; + node="1"; + modelnet_simplenet@foo="1"; + } + FOO_FORWARDERS { + repetitions="4"; + forwarder="1"; + modelnet_simplenet@foo="1"; + modelnet_simplenet="1"; + } + ## cluster bar + BAR_CLUSTER { + repetitions="12"; + node="1"; + modelnet_simplenet@bar="1"; + } + BAR_FORWARDERS { + repetitions="4"; + forwarder="1"; + modelnet_simplenet@bar="1"; + modelnet_simplenet="1"; + } +} + +PARAMS { + ## ROSS parameters + message_size="256"; + + ## global modelnet parameters + modelnet_order=("simplenet"); + + ## foo cluster network parameters + packet_size@foo="8192"; + modelnet_scheduler@foo="fcfs"; + net_startup_ns@foo="1.5"; + net_bw_mbps@foo="10000"; + + ## bar cluster network parameters + packet_size@bar="2048"; + modelnet_scheduler@bar="round-robin"; + net_startup_ns@bar="3.0"; + net_bw_mbps@bar="15000"; + + ## forwarding network parameters + packet_size="4096"; + modelnet_scheduler="fcfs"; + net_startup_ns="8.0"; + net_bw_mbps="5000"; +} + +run_params { + num_reqs="5"; + payload_sz="16384"; +} diff --git a/doc/example_heterogeneous/example_torus.conf b/doc/example_heterogeneous/example_torus.conf new file mode 100644 index 0000000000000000000000000000000000000000..28bb759ab375563dd6410718858cbeb84e048f1e --- /dev/null +++ b/doc/example_heterogeneous/example_torus.conf @@ -0,0 +1,65 @@ +LPGROUPS { + ## cluster foo + FOO_CLUSTER { + repetitions="12"; + node="1"; + modelnet_torus@foo="1"; + } + FOO_FORWARDERS { + repetitions="4"; + forwarder="1"; + modelnet_torus@foo="1"; + modelnet_simplenet="1"; + } + ## cluster bar + BAR_CLUSTER { + repetitions="12"; + node="1"; + modelnet_torus@bar="1"; + } + BAR_FORWARDERS { + repetitions="4"; + forwarder="1"; + modelnet_torus@bar="1"; + modelnet_simplenet="1"; + } +} + +PARAMS { + ## ROSS parameters + message_size="256"; + + ## global modelnet parameters + modelnet_order=("torus","simplenet"); + + ## foo cluster network parameters + packet_size@foo="8192"; + modelnet_scheduler@foo="fcfs"; + n_dims@foo="3"; + dim_length@foo="4,2,2"; + link_bandwidth@foo="2.0"; + buffer_size@foo="8192"; + num_vc@foo="1"; + chunk_size@foo="32"; + + ## bar cluster network parameters + packet_size@bar="2048"; + modelnet_scheduler@bar="round-robin"; + n_dims@bar="2"; + dim_length@bar="4,4"; + link_bandwidth@bar="2.0"; + buffer_size@bar="8192"; + num_vc@bar="1"; + chunk_size@bar="32"; + + ## forwarding network parameters + packet_size="4096"; + modelnet_scheduler="fcfs"; + net_startup_ns="8.0"; + net_bw_mbps="5000"; +} + +run_params { + num_reqs="5"; + payload_sz="16384"; +} diff --git a/doc/workload/example.kernel.txt b/doc/workload/example.kernel.txt new file mode 100644 index 0000000000000000000000000000000000000000..68be4cdc1c5fb039f55395856c5a9610e8d6a26e --- /dev/null +++ b/doc/workload/example.kernel.txt @@ -0,0 +1,17 @@ +r = getgrouprank -1; +s = getgroupsize -1; +f = 13; + +b = 4194304; + +open f; + +writeat f, b, (r*b); + +sync f; + +readat f, b, ((s-r-1)*b); + +close f; + +exit 0; diff --git a/doc/workload/meta.txt b/doc/workload/meta.txt new file mode 100644 index 0000000000000000000000000000000000000000..16cb3bebb6d853cc91a720236295766bfe845c7d --- /dev/null +++ b/doc/workload/meta.txt @@ -0,0 +1 @@ +1 0 -1 example.kernel.txt diff --git a/m4/ax_compare_version.m4 b/m4/ax_compare_version.m4 new file mode 100644 index 0000000000000000000000000000000000000000..74dc0fdd9a40cea41852e138d687b43a05492bd9 --- /dev/null +++ b/m4/ax_compare_version.m4 @@ -0,0 +1,177 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_compare_version.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_COMPARE_VERSION(VERSION_A, OP, VERSION_B, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) +# +# DESCRIPTION +# +# This macro compares two version strings. Due to the various number of +# minor-version numbers that can exist, and the fact that string +# comparisons are not compatible with numeric comparisons, this is not +# necessarily trivial to do in a autoconf script. This macro makes doing +# these comparisons easy. +# +# The six basic comparisons are available, as well as checking equality +# limited to a certain number of minor-version levels. +# +# The operator OP determines what type of comparison to do, and can be one +# of: +# +# eq - equal (test A == B) +# ne - not equal (test A != B) +# le - less than or equal (test A <= B) +# ge - greater than or equal (test A >= B) +# lt - less than (test A < B) +# gt - greater than (test A > B) +# +# Additionally, the eq and ne operator can have a number after it to limit +# the test to that number of minor versions. +# +# eq0 - equal up to the length of the shorter version +# ne0 - not equal up to the length of the shorter version +# eqN - equal up to N sub-version levels +# neN - not equal up to N sub-version levels +# +# When the condition is true, shell commands ACTION-IF-TRUE are run, +# otherwise shell commands ACTION-IF-FALSE are run. The environment +# variable 'ax_compare_version' is always set to either 'true' or 'false' +# as well. +# +# Examples: +# +# AX_COMPARE_VERSION([3.15.7],[lt],[3.15.8]) +# AX_COMPARE_VERSION([3.15],[lt],[3.15.8]) +# +# would both be true. +# +# AX_COMPARE_VERSION([3.15.7],[eq],[3.15.8]) +# AX_COMPARE_VERSION([3.15],[gt],[3.15.8]) +# +# would both be false. +# +# AX_COMPARE_VERSION([3.15.7],[eq2],[3.15.8]) +# +# would be true because it is only comparing two minor versions. +# +# AX_COMPARE_VERSION([3.15.7],[eq0],[3.15]) +# +# would be true because it is only comparing the lesser number of minor +# versions of the two values. +# +# Note: The characters that separate the version numbers do not matter. An +# empty string is the same as version 0. OP is evaluated by autoconf, not +# configure, so must be a string, not a variable. +# +# The author would like to acknowledge Guido Draheim whose advice about +# the m4_case and m4_ifvaln functions make this macro only include the +# portions necessary to perform the specific comparison specified by the +# OP argument in the final configure script. +# +# LICENSE +# +# Copyright (c) 2008 Tim Toolan +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 11 + +dnl ######################################################################### +AC_DEFUN([AX_COMPARE_VERSION], [ + AC_REQUIRE([AC_PROG_AWK]) + + # Used to indicate true or false condition + ax_compare_version=false + + # Convert the two version strings to be compared into a format that + # allows a simple string comparison. The end result is that a version + # string of the form 1.12.5-r617 will be converted to the form + # 0001001200050617. In other words, each number is zero padded to four + # digits, and non digits are removed. + AS_VAR_PUSHDEF([A],[ax_compare_version_A]) + A=`echo "$1" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ + -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/[[^0-9]]//g'` + + AS_VAR_PUSHDEF([B],[ax_compare_version_B]) + B=`echo "$3" | sed -e 's/\([[0-9]]*\)/Z\1Z/g' \ + -e 's/Z\([[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/Z\([[0-9]][[0-9]][[0-9]]\)Z/Z0\1Z/g' \ + -e 's/[[^0-9]]//g'` + + dnl # In the case of le, ge, lt, and gt, the strings are sorted as necessary + dnl # then the first line is used to determine if the condition is true. + dnl # The sed right after the echo is to remove any indented white space. + m4_case(m4_tolower($2), + [lt],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/false/;s/x${B}/true/;1q"` + ], + [gt],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort | sed "s/x${A}/false/;s/x${B}/true/;1q"` + ], + [le],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort | sed "s/x${A}/true/;s/x${B}/false/;1q"` + ], + [ge],[ + ax_compare_version=`echo "x$A +x$B" | sed 's/^ *//' | sort -r | sed "s/x${A}/true/;s/x${B}/false/;1q"` + ],[ + dnl Split the operator from the subversion count if present. + m4_bmatch(m4_substr($2,2), + [0],[ + # A count of zero means use the length of the shorter version. + # Determine the number of characters in A and B. + ax_compare_version_len_A=`echo "$A" | $AWK '{print(length)}'` + ax_compare_version_len_B=`echo "$B" | $AWK '{print(length)}'` + + # Set A to no more than B's length and B to no more than A's length. + A=`echo "$A" | sed "s/\(.\{$ax_compare_version_len_B\}\).*/\1/"` + B=`echo "$B" | sed "s/\(.\{$ax_compare_version_len_A\}\).*/\1/"` + ], + [[0-9]+],[ + # A count greater than zero means use only that many subversions + A=`echo "$A" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` + B=`echo "$B" | sed "s/\(\([[0-9]]\{4\}\)\{m4_substr($2,2)\}\).*/\1/"` + ], + [.+],[ + AC_WARNING( + [illegal OP numeric parameter: $2]) + ],[]) + + # Pad zeros at end of numbers to make same length. + ax_compare_version_tmp_A="$A`echo $B | sed 's/./0/g'`" + B="$B`echo $A | sed 's/./0/g'`" + A="$ax_compare_version_tmp_A" + + # Check for equality or inequality as necessary. + m4_case(m4_tolower(m4_substr($2,0,2)), + [eq],[ + test "x$A" = "x$B" && ax_compare_version=true + ], + [ne],[ + test "x$A" != "x$B" && ax_compare_version=true + ],[ + AC_WARNING([illegal OP parameter: $2]) + ]) + ]) + + AS_VAR_POPDEF([A])dnl + AS_VAR_POPDEF([B])dnl + + dnl # Execute ACTION-IF-TRUE / ACTION-IF-FALSE. + if test "$ax_compare_version" = "true" ; then + m4_ifvaln([$4],[$4],[:])dnl + m4_ifvaln([$5],[else $5])dnl + fi +]) dnl AX_COMPARE_VERSION diff --git a/m4/ax_prog_bison.m4 b/m4/ax_prog_bison.m4 new file mode 100755 index 0000000000000000000000000000000000000000..aa3bb112b08bbf175fd5a6e1ebfaee1adf997a24 --- /dev/null +++ b/m4/ax_prog_bison.m4 @@ -0,0 +1,68 @@ +# =========================================================================== +# http://www.nongnu.org/autoconf-archive/ax_prog_bison.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_BISON(ACTION-IF-TRUE,ACTION-IF-FALSE) +# +# DESCRIPTION +# +# Check whether bison is the parser generator. Run ACTION-IF-TRUE if +# successful, ACTION-IF-FALSE otherwise +# +# LICENSE +# +# Copyright (c) 2009 Francesco Salvestrini +# +# 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 of the License, 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. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_PROG_BISON], [ + AC_REQUIRE([AC_PROG_YACC]) + AC_REQUIRE([AC_PROG_SED]) + + AC_CACHE_CHECK([if bison is the parser generator],[ax_cv_prog_bison],[ + AS_IF([test "`echo \"$YACC\" | $SED 's,^.*\(bison\).*$,\1,'`" = "bison" ],[ + ax_cv_prog_bison=yes + ],[ + ax_cv_prog_bison=no + ]) + ]) + + AC_DEFINE([HAVE_YACC_OLD_PUSH],[0],[If old-style push parser syntax is supported by ${YACC}]) + AM_CONDITIONAL([HAVE_YACC_OLD_PUSH],[test "x${HAVE_YACC_OLD_PUSH}" == "x1"]) + AC_DEFINE([HAVE_YACC_OLD_PURE],[0],[If old-style pure reentrant parser syntax is supported by ${YACC}]) + AM_CONDITIONAL([HAVE_YACC_OLD_PURE],[test "x${HAVE_YACC_OLD_PURE}" == "x1"]) + + AS_IF([test "$ax_cv_prog_bison" = yes],[ + : + $1 + ],[ + : + $2 + ]) +]) diff --git a/m4/ax_prog_bison_clfeatures.m4 b/m4/ax_prog_bison_clfeatures.m4 new file mode 100755 index 0000000000000000000000000000000000000000..46e826651a1f8a57b3a5d7c733decebbf3b5075e --- /dev/null +++ b/m4/ax_prog_bison_clfeatures.m4 @@ -0,0 +1,137 @@ +AC_DEFUN([AX_PROG_BISON_CLFEATURES], [ + AC_REQUIRE([AC_PROG_YACC]) + AC_REQUIRE([AC_PROG_SED]) + + AC_CACHE_CHECK([if bison is the parser generator],[ax_cv_prog_bison],[ + AS_IF([test "`echo \"$YACC\" | $SED 's,^.*\(bison\).*$,\1,'`" = "bison" ],[ + ax_cv_prog_bison=yes + ],[ + ax_cv_prog_bison=no + ]) + ]) + +cat > conftest.y < /dev/null 2>&1 && eval "$ac_compile_yacc" +then + AC_SUBST([CODES_PURE_PARSER_DEFINES], ["%pure-parser"]) + AC_MSG_RESULT([old-style]) + $3 +else + +cat > conftest.y < /dev/null 2>&1 && eval "$ac_compile_yacc" + then + AC_SUBST([CODES_PURE_PARSER_DEFINES], ["%define api.pure"]) + AC_MSG_RESULT([new-style]) + $3 + else + AC_MSG_RESULT([feature not supported]) + BVER=`${YACC} --version | head -n 1` + AC_MSG_WARN([${BVER} does not support pure / reentrant parser generation]) + $4 + fi +fi + +cat > conftest.y < /dev/null 2>&1 && eval "$ac_compile_yacc" +then + AC_SUBST([CODES_PUSH_PARSER_DEFINES], ["%define api.push_pull \"push\""]) + AC_MSG_RESULT([old-style]) + $3 +else + +cat > conftest.y < /dev/null 2>&1 && eval "$ac_compile_yacc" + then + AC_SUBST([CODES_PUSH_PARSER_DEFINES], ["%define api.push-pull push"]) + AC_MSG_RESULT([new-style]) + $3 + else + AC_MSG_RESULT([feature not supported]) + BVER=`${YACC} --version | head -n 1` + AC_MSG_WARN([${BVER} does not support push parser generation]) + $4 + fi +fi + + AS_IF([test "$ax_cv_prog_bison" = yes],[ + : + $1 + ],[ + : + $2 + ]) + + # cleanup bison / yacc tmp files + rm -rf y.output y.tab.h y.tab.c y.tab.o +]) diff --git a/m4/ax_prog_flex.m4 b/m4/ax_prog_flex.m4 new file mode 100755 index 0000000000000000000000000000000000000000..6f8c6107669e53576886173539e441ec604395a6 --- /dev/null +++ b/m4/ax_prog_flex.m4 @@ -0,0 +1,62 @@ +# =========================================================================== +# http://www.nongnu.org/autoconf-archive/ax_prog_flex.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_FLEX(ACTION-IF-TRUE,ACTION-IF-FALSE) +# +# DESCRIPTION +# +# Check whether flex is the scanner generator. Run ACTION-IF-TRUE if +# successful, ACTION-IF-FALSE otherwise +# +# LICENSE +# +# Copyright (c) 2009 Francesco Salvestrini +# +# 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 of the License, 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. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +AC_DEFUN([AX_PROG_FLEX], [ + AC_REQUIRE([AC_PROG_LEX]) + AC_REQUIRE([AC_PROG_SED]) + + AC_CACHE_CHECK([if flex is the lexer generator],[ax_cv_prog_flex],[ + AS_IF([test "`echo \"$LEX\" | $SED 's,^.*\(flex\).*$,\1,'`" = "flex"],[ + ax_cv_prog_flex=yes + ],[ + ax_cv_prog_flex=no + ]) + ]) + AS_IF([test "$ax_cv_prog_flex" = yes],[ + : + $1 + ],[ + : + $2 + ]) +]) diff --git a/m4/pkg.m4 b/m4/pkg.m4 new file mode 100644 index 0000000000000000000000000000000000000000..62995f01f445b8bc586412dc71f480928e4f9519 --- /dev/null +++ b/m4/pkg.m4 @@ -0,0 +1,233 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 1 (pkg-config-0.24) +# +# Copyright © 2004 Scott James Remnant . +# +# 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 of the License, 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. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +# only at the first occurence in configure.ac, so if the first place +# it's called might be skipped (such as if it is within an "if", you +# have to call PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])# PKG_CHECK_MODULES + + +# PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# --------------------------------------------------------------------- +# Checks for existence of MODULES and gathers its build flags with +# static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags +# and VARIABLE-PREFIX_LIBS from --libs. +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES_STATIC might not happen, you should be sure to include +# an explicit call to PKG_PROG_PKG_CONFIG in your configure.ac. +AC_DEFUN([PKG_CHECK_MODULES_STATIC], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +_save_PKG_CONFIG=$PKG_CONFIG +PKG_CONFIG="$PKG_CONFIG --static" +PKG_CHECK_MODULES($@) +PKG_CONFIG=$_save_PKG_CONFIG[]dnl +]) + + +# PKG_INSTALLDIR(DIRECTORY) +# ------------------------- +# Substitutes the variable pkgconfigdir as the location where a module +# should install pkg-config .pc files. By default the directory is +# $libdir/pkgconfig, but the default can be changed by passing +# DIRECTORY. The user can override through the --with-pkgconfigdir +# parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +]) dnl PKG_INSTALLDIR + + +# PKG_NOARCH_INSTALLDIR(DIRECTORY) +# ------------------------- +# Substitutes the variable noarch_pkgconfigdir as the location where a +# module should install arch-independent pkg-config .pc files. By +# default the directory is $datadir/pkgconfig, but the default can be +# changed by passing DIRECTORY. The user can override through the +# --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +]) dnl PKG_NOARCH_INSTALLDIR + + +# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, +# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# ------------------------------------------- +# Retrieves the value of the pkg-config variable for the given module. +AC_DEFUN([PKG_CHECK_VAR], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl + +_PKG_CONFIG([$1], [variable="][$3]["], [$2]) +AS_VAR_COPY([$1], [pkg_cv_][$1]) + +AS_VAR_IF([$1], [""], [$5], [$4])dnl +])# PKG_CHECK_VAR diff --git a/maint/codes-base.pc.in b/maint/codes-base.pc.in new file mode 100644 index 0000000000000000000000000000000000000000..ab16e18625f6698b168257ab4060e2b623ec9a06 --- /dev/null +++ b/maint/codes-base.pc.in @@ -0,0 +1,18 @@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ +ross_cflags=@ROSS_CFLAGS@ +ross_libs=@ROSS_LIBS@ +darshan_libs=@DARSHAN_LIBS@ +darshan_cflags=@DARSHAN_CFLAGS@ +dumpi_cflags=@DUMPI_CFLAGS@ +dumpi_libs=@DUMPI_LIBS@ + +Name: codes-base +Description: Base functionality for CODES storage simulation +Version: @PACKAGE_VERSION@ +URL: http://trac.mcs.anl.gov/projects/CODES +Requires: +Libs: -L${libdir} -lcodes-base ${ross_libs} ${darshan_libs} ${dumpi_libs} +Cflags: -I${includedir} ${ross_cflags} ${darshan_cflags} ${dumpi_cflags} diff --git a/prepare.sh b/prepare.sh new file mode 100755 index 0000000000000000000000000000000000000000..2739136e0b6d102f4ef5f3a1ace52bc43d091857 --- /dev/null +++ b/prepare.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +echo "Regenerating build files..." +autoreconf -fi -Im4 diff --git a/reformat.sh b/reformat.sh new file mode 100755 index 0000000000000000000000000000000000000000..fde8467f381044d17e871d45e47db4ed59d5b252 --- /dev/null +++ b/reformat.sh @@ -0,0 +1,109 @@ +#!/bin/bash + +script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +function error () { + echo "ERROR: $@" >&2 + exit 1 +} + +function usage() { + cat \ +< /dev/null 2>&1 || error "uncrustify not found" + +do_inplace=no +do_recursive=no +do_check=no +blacklist= + +while getopts ":ib:axh" opt; do + case $opt in + i) + do_inplace=yes + ;; + b) + blacklist=$(cat $OPTARG | sed s/,/ /g) + ;; + c) + cfg=$OPTARG + ;; + a) + do_recursive=yes + ;; + x) + do_check=yes + ;; + h) + usage + exit 1 + ;; + \?) + usage + error "invalid argument: -$OPTARG" + ;; + esac +done + +shift $((OPTIND-1)) + +[[ -e $cfg ]] || ( usage && error "config file $cfg not found" ) + +[[ $# -gt 0 && $do_recursive == yes ]] && \ + usage && error "no file args expected in recursive mode" +[[ $# -eq 0 && $do_recursive == no ]] && \ + usage && error "expected file args in non-recursive mode" + +if [[ $do_recursive == yes ]] ; then + file_list="$(getfiles $blacklist)" +else + file_list="$@" +fi + +if [[ $do_recursive == yes && $do_inplace == yes ]] ; then + echo -n "Do recursive in-place reformat? (y/n) " + read answer + [[ $answer =~ "[^y].*" ]] && echo "...aborting reformat" && exit 1 +fi + +[[ $do_inplace == yes ]] \ + && output_arg="--replace" \ + || output_arg= + +if [[ $do_check == yes ]] ; then + check_arg=--check + output_arg= + echo "checking format..." +else + check_arg= +fi + +function echolines () { + for x in $@ ; do echo $x ; done +} + +echolines $file_list | uncrustify $check_arg -c $cfg $output_arg -F - diff --git a/scripts/Makefile.subdir b/scripts/Makefile.subdir new file mode 100644 index 0000000000000000000000000000000000000000..f2c388f85ca4d5aa804894fe3b6a1973113be780 --- /dev/null +++ b/scripts/Makefile.subdir @@ -0,0 +1,29 @@ +my_bin_scripts = scripts/codes_configurator \ + scripts/codes_filter_configs \ + scripts/codes_config_get_vals + +bin_SCRIPTS += $(my_bin_scripts) +EXTRA_DIST += scripts/codes_configurator.py.in \ + scripts/codes_filter_configs.py.in \ + scripts/codes_config_get_vals.py.in \ + scripts/configurator.py +CLEANFILES += $(my_bin_scripts) + +# manual rules for now +do_subst = sed -e 's![@]libdir[@]!$(libdir)!g' + +.PHONY: scriptdir +# need to ensure that the scripts directory exists before running the sub cmd +scriptdir: + test -d scripts || mkdir scripts + +%: %.py.in Makefile scriptdir + $(do_subst) < $< > $@ + chmod +x $@ + +# install hook for configurator utility lib +# TODO: actually use the install program, use more of a 'standard' approach +install-data-local: + cp $(top_srcdir)/scripts/configurator.py $(libdir) +uninstall-local: + rm -f $(libdir)/configurator.py diff --git a/scripts/codes_config_get_vals.py.in b/scripts/codes_config_get_vals.py.in new file mode 100644 index 0000000000000000000000000000000000000000..36587f1d4436169c5631cac3738669ed9bda0fd3 --- /dev/null +++ b/scripts/codes_config_get_vals.py.in @@ -0,0 +1,61 @@ +#!/usr/bin/python2.7 + +# +# Copyright (C) 2014 University of Chicago. +# See COPYRIGHT notice in top-level directory. +# +# + +import argparse +import sys +import os +import imp +from itertools import islice + +# internal testing: import directly +#import configurator as conf + +# internal testing: import directly +#import configurator as conf + +# dynamically load from lib path +def import_from(fname): + path,name = os.path.split(fname) + name,ext = os.path.splitext(name) + + fmod, fname, data = imp.find_module(name, [path]) + return imp.load_module(name,fmod,fname,data) + +conf = import_from("@libdir@/configurator.py") + +def main(): + args = parse_args() + + mod = conf.import_from(args.substitute_py) + + conf.check_cfields(mod) + + for pair in mod.cfields: + if pair[0] == args.token: + sys.stdout.write(str(pair[1][0])) + for x in islice(pair[1],1,None): + sys.stdout.write(" " + str(x)) + sys.stdout.write('\n') + sys.exit(0) # success + else: # failure, did not find + raise ValueError('could not find token "' + args.token + '"') + + +def parse_args(): + parser = argparse.ArgumentParser(\ + description="echo the values of a token file to stdout") + parser.add_argument("substitute_py", + help='python file defining "cfields" variable consisting of ' + 'elements of the form ' + '( replacement_token, [replacements...])') + parser.add_argument("token", + help="replacement token to print values out for") + return parser.parse_args() + +if __name__ == "__main__": + main() diff --git a/scripts/codes_configurator.py.in b/scripts/codes_configurator.py.in new file mode 100644 index 0000000000000000000000000000000000000000..e4f2daec5dc9c13b8f05d1d56c3144f72aa5d796 --- /dev/null +++ b/scripts/codes_configurator.py.in @@ -0,0 +1,92 @@ +#!/usr/bin/python2.7 + +# +# Copyright (C) 2014 University of Chicago. +# See COPYRIGHT notice in top-level directory. +# +# + +import os +import argparse +import imp + +# internal testing: import directly +#import configurator as conf + +# dynamically load from lib path +def import_from(fname): + path,name = os.path.split(fname) + name,ext = os.path.splitext(name) + + fmod, fname, data = imp.find_module(name, [path]) + return imp.load_module(name,fmod,fname,data) + +conf = import_from("@libdir@/configurator.py") + +def main(): + args = parse_args() + + # load the template file + tstr = open(args.template).read() + + # load the module + mod = conf.import_from(args.substitute_py) + + # intitialize the configuration object + cfg = conf.configurator(mod, args.token_pairs) + + # print the header to the log + if args.log != None: + flog = open(args.log, "w") + else: + flog = open(os.devnull, "w") + + cfg.write_header(flog) + + # main loop (cfg iterator returns nothing, eval'd for side effects) + for i,_ in enumerate(cfg): + new_config = conf.replace_many(tstr, cfg.replace_map) + fname = template+"."+str(i) if args.output_prefix==None else \ + args.output_prefix +"." + "{:05d}".format(i) + with open(fname, "w") as fout: + fout.write(new_config) + + # write this config to the log + cfg.write_config_line(i, flog) + + flog.close() + +sub_help = \ +'python file defining "cfields" variable consisting of a sequence of pairs. The following variables may optionally appear. ' \ +'"exceptions" - a sequence of dictionaries. Each configuration generated by ' \ +'"cfields" is checked against each dictionary in "exceptions"; if each value ' \ +'in the dict matches that of the configuration, then that configuration is ' \ +'skipped. "cfields_derived_labels", "cfields_derived" - the former is a ' \ +'sequence of strings identifying replace tokens that will be dynamically set ' \ +'based on the input configuration generated by cfields. The latter is a ' \ +'function that adds all pairs for names in ' \ +'"cfields_derived_labels".' + +def parse_args(): + parser = argparse.ArgumentParser(\ + description="generate set of configuration files based on template " + "file and replacement tokens") + parser.add_argument("template", + help="template file with replace tokens") + parser.add_argument("substitute_py", + help=sub_help) + parser.add_argument("token_pairs", nargs='*', + help="a list of whitespace-separated token, replace pairs for " + "command-line-driven replacement (useful in shell scripts " + "for generating sets of configuration files with a distinct " + "parameter or for special casing fields)") + parser.add_argument("-l", "--log", + help="log file to write parameterizations to") + parser.add_argument("-o", "--output_prefix", + help="prefix to output generated configuration files to " + "(default: the configuration index appended to the template name)") + return parser.parse_args() + +if __name__ == "__main__": + main() diff --git a/scripts/codes_filter_configs.py.in b/scripts/codes_filter_configs.py.in new file mode 100644 index 0000000000000000000000000000000000000000..c8e786b1b749d69095b01c67c0f0b330bb99ad36 --- /dev/null +++ b/scripts/codes_filter_configs.py.in @@ -0,0 +1,80 @@ +#!/usr/bin/python2.7 + +# +# Copyright (C) 2014 University of Chicago. +# See COPYRIGHT notice in top-level directory. +# +# + +from sys import stdout +import os +import argparse +import imp + +# internal testing: import directly +#import configurator as conf + +# dynamically load from lib path +def import_from(fname): + path,name = os.path.split(fname) + name,ext = os.path.splitext(name) + + fmod, fname, data = imp.find_module(name, [path]) + return imp.load_module(name,fmod,fname,data) + +conf = import_from("@libdir@/configurator.py") + +def main(): + args = parse_args() + + # load and check the module + mod = conf.import_from(args.substitute_py) + conf.check_cfields(mod) + + # check that pairs are actually pairs + tp = args.token_pairs + if len(tp) % 2 != 0: + raise ValueError("token pairs must come in twos") + + # intitialize the configuration object + cfg = conf.configurator(mod, []) + + # build a lookup structure for the pairs, converting to numbers if + # possible + tdict = { } + for i in range(0, len(tp), 2): + v = conf.try_num(tp[i+1]) + if v == None: + v = tp[i+1] + tdict[tp[i]] = v + + # hack - if we are using an output prefix, append the "dot" here + if args.output_prefix == None: + args.output_prefix = "" + else: + args.output_prefix = args.output_prefix + '.' + # filter out the files + # (cfg iterator returns nothing, eval'd for side effects) + for i,_ in enumerate(cfg): + for k in tdict: + if k not in cfg.replace_map or tdict[k] != cfg.replace_map[k]: + break + else: + stdout.write(args.output_prefix + "{:05d}".format(i) + "\n") + +def parse_args(): + parser = argparse.ArgumentParser(\ + description="emit configuration files to stdout matching given " + "token values") + parser.add_argument("-o", "--output_prefix", help="prefix of output config " + "files (Default: print only the filtered indices)", type=str) + parser.add_argument("substitute_py", + help="input python file given to codes_configurator.py - see " + "codes_configurator.py for details") + parser.add_argument("token_pairs", nargs='*', + help="a list of whitespace-separated token, replace pairs to " + "filter the set of generated configuration files by") + return parser.parse_args() + +if __name__ == "__main__": + main() diff --git a/scripts/configurator.py b/scripts/configurator.py new file mode 100644 index 0000000000000000000000000000000000000000..b06e1152ac42951dc5e75a5583f862d40c2060de --- /dev/null +++ b/scripts/configurator.py @@ -0,0 +1,196 @@ +""" Helpers and utilities for use by codes_configurator and friends """ + +# +# Copyright (C) 2013 University of Chicago. +# See COPYRIGHT notice in top-level directory. +# +# + +import re +import os +import imp +from collections import Sequence + +class configurator: + # note: object assumes input has been validated by caller, though it will + # still throw if it finds duplicate keys in the dict + def __init__(self, module, replace_pairs): + # checks - check cfields and friends + check_cfields(module) + # check that pairs are actually pairs + if len(replace_pairs) % 2 != 0: + raise ValueError("token pairs must come in twos") + + self.mod = module + # simplify None-checking for cfields by generating an empty tuple + # instead + if self.mod.cfields == None: + self.mod.cfields = () + self.num_fields = len(self.mod.cfields) + self.labels = [k[0] for k in self.mod.cfields] + replace_pairs[0::2] + self.replace_map = { k[0] : None for k in self.mod.cfields } + self.start_iter = False + self.in_iter = False + self.has_except = "excepts" in self.mod.__dict__ + self.has_derived = "cfields_derived_labels" in self.mod.__dict__ and \ + "cfields_derived" in self.mod.__dict__ + + for i in range(0, len(replace_pairs), 2): + k,vstr = replace_pairs[i], replace_pairs[i+1] + # add pair to replace map and labels (but not iterables!) + if k in self.replace_map: + raise ValueError("token " + k + " of token_pairs matches a token " + "given by the substitution py file") + # try making v numeric - fall back to string + v = try_num(vstr) + if v == None: + v = vstr + self.replace_map[k] = v + + # initialize derived labels if necessary + if self.has_derived: + self.labels += [l for l in self.mod.cfields_derived_labels] + + + def __iter__(self): + self.start_iter = True + self.in_iter = True + return self + def next(self): + if not self.in_iter: + # either uninitialized or at the end of the road + raise StopIteration + elif self.start_iter: + # first iteration - initialize the iterators + self.iterables = [k[1].__iter__() for k in self.mod.cfields] + for i in range(0, self.num_fields): + v = self.iterables[i].next() + self.replace_map[self.labels[i]] = v + self.start_iter = False + else: + # > first iteration, perform the updates + # generate the next config + for i in range(0,self.num_fields): + try: + # update current iterable and finish + v = self.iterables[i].next() + self.replace_map[self.labels[i]] = v + break + except StopIteration: + # reset the current iterable and set to first element + self.iterables[i] = self.mod.cfields[i][1].__iter__() + v = self.iterables[i].next() + self.replace_map[self.labels[i]] = v + else: + # last iterable has finished, have generated full set + raise StopIteration + # add derived fields before exceptions + if self.has_derived: + self.mod.cfields_derived(self.replace_map) + # check if this is a valid config, if not, then recurse + if self.has_except and is_replace_except(self.mod.excepts, + self.replace_map): + return self.next() + else: + return None + + def write_header(self, fout): + fout.write("# format:\n# ") + for l in self.labels: + fout.write(" <" + l + ">") + fout.write("\n") + + def write_config_line(self, ident, fout): + # print the configuration to the log + fout.write(str(ident)) + for l in self.labels: + fout.write(' ' + str(self.replace_map[l])) + else: + fout.write('\n') + +def is_replace_except(except_map, replace_map): + for d in except_map: + for k in d: + if d[k] != replace_map[k]: + break + else: + return True + return False + +# checks - make sure cfields is set and is the correct type +# note: cfields can be None or an empty sequence +def check_cfields(module): + if "cfields" not in module.__dict__: + raise TypeError("Expected cfields to be defined in " + str(module)) + elif module.cfields == None or \ + (isinstance(module.cfields, Sequence) and len(module.cfields) == 0): + return + elif not \ + (isinstance(module.cfields, Sequence) and \ + isinstance(module.cfields[0][0], str) and \ + isinstance(module.cfields[0][1], Sequence)): + raise TypeError("cfields in incorrect format, see usage") + + if "excepts" in module.__dict__ and not \ + (isinstance(module.excepts, Sequence) and\ + isinstance(module.excepts[0], dict)) : + raise TypeError("excepts not in correct format, see usage") + + dl = "cfields_derived_labels" in module.__dict__ + d = "cfields_derived" in module.__dict__ + if (dl and not d) or (not dl and d): + raise TypeError("both cfields_derived_labels and cfields_derived must " + "be set") + elif dl and d and not \ + (isinstance(module.cfields_derived_labels, Sequence) and \ + isinstance(module.cfields_derived_labels[0], str) and \ + hasattr(module.cfields_derived, "__call__")): + raise TypeError("cfields_derived_labels must be a sequence of " + "strings, cfields_derived must be callable (accepting a " + "dict of replace_token, replacement pairs and adding pairs " + "for each label in cfields_derived_labels") + + + +# import a python file (assumes there is a .py suffix!!!) +def import_from(filename): + path,name = os.path.split(filename) + name,ext = os.path.splitext(name) + + fmod, fname, data = imp.find_module(name, [path]) + return imp.load_module(name,fmod,fname,data) + +# attempts casting to a numeric type, returning None on failure +def try_num(s): + try: + return int(s) + except ValueError: + try: + return float(s) + except ValueError: + return None + +# given a string and a set of substitution pairs, +# perform a single pass replace +# st is the string to perform substitution on +# kv_pairs is a dict or a sequence of sequences. +# kv_pairs examples: +# { a:b, c:d } +# [[a,b],[c,d]] +# [(a,b),(c,d)] +# ((a,b),(c,d)) +def replace_many(st, kv_pairs): + rep_dict = {} + # dict-ify and string-ify the input + if isinstance(kv_pairs, dict): + for k in kv_pairs: + rep_dict[k] = str(kv_pairs[k]) + elif isinstance(kv_pairs, Sequence) and isinstance(kv_pairs[0], Sequence): + for k in kv_pairs: + rep_dict[k[0]] = str(kv_pairs[k[1]]) + else: + raise TypeError("Expected dict or sequence of sequences types") + + pat = re.compile("|".join([re.escape(k) for k in rep_dict])) + + return pat.sub(lambda match: rep_dict[match.group(0)], st) diff --git a/scripts/example/example.template b/scripts/example/example.template new file mode 100644 index 0000000000000000000000000000000000000000..a683837189e655decec4c69870a4359484301150 --- /dev/null +++ b/scripts/example/example.template @@ -0,0 +1,46 @@ +# the LPGROUPS set is required by all simulations using codes. Multiple groups +# can be entered (only one is here for our example), each consisting of a set +# of application- and codes-specific key-value pairs. +LPGROUPS +{ + # in our simulation, we simply have a set of servers, each with + # point-to-point access to each other + SERVERS + { + # required: number of times to repeat the following key-value pairs + repetitions="C_NUM_SERVERS"; + # application-specific: parsed in main + server="1"; + # model-net-specific field defining the network backend. In this example, + # each server has one NIC, and each server are point-to-point connected + modelnet_simplenet="1"; + } +} +# required by CODES: miscellaneous parameters used in the simulation that +# don't fit in group definition. +PARAMS +{ + # ROSS-specific parmeters: + # - message_size: ROSS expects you to upper bound your event message size. + # Going over this size will crash or otherwise destroy your + # simulation. + message_size="256"; + # model-net-specific parameters: + # - individual packet sizes for network operations + # (each "packet" is represented by an event) + # - independent of underlying network being used + packet_size="C_PACKET_SZ"; + # - type of model to use (must match with corresponding LPGROUPS entry) + modelnet="simplenet"; + # - model-specific parameters + net_startup_ns="1.5"; + net_bw_mbps="20000"; +} + +# custom parameter sets can also be added - this one is used to define the +# rounds of communication the servers will undergo +server_pings +{ + num_reqs="C_NUM_REQS"; + payload_sz="C_PAYLOAD_SZ"; +} diff --git a/scripts/example/params.py b/scripts/example/params.py new file mode 100644 index 0000000000000000000000000000000000000000..fed1dd8c778a749b723954827f5384b79e225751 --- /dev/null +++ b/scripts/example/params.py @@ -0,0 +1,11 @@ +cfields = ( ("C_NUM_SERVERS", [1<scanner + +extern int64_t * sym; +extern int64_t * var; +extern int * inst_ready; +extern int * group_rank; +extern int * group_size; +extern int temp_group_rank; +extern int temp_group_size; +#endif + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/iokernellang/CodesKernelHelpers.c b/src/iokernellang/CodesKernelHelpers.c new file mode 100644 index 0000000000000000000000000000000000000000..5601daa019e090c4c4c943c158109c426a6682a9 --- /dev/null +++ b/src/iokernellang/CodesKernelHelpers.c @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include "CodesKernelHelpers.h" + +#include +#include +#include +#include +#include +#include +#include + +#define CK_LINE_LIMIT 8192 +#define CL_DEFAULT_GID 0 + +char * code_kernel_helpers_kinstToStr(int inst) +{ + switch(inst) + { + case WRITEAT: + return "WRITEAT"; + case READAT: + return "READAT"; + case GETGROUPRANK: + return "GETGROUPRANK"; + case GETGROUPSIZE: + return "GETGROUPSIZE"; + case CLOSE: + return "CLOSE"; + case OPEN: + return "OPEN"; + case SYNC: + return "SYNC"; + case SLEEP: + return "SLEEP"; + case EXIT: + return "EXIT"; + case DELETE: + return "DELETE"; + default: + return "UNKNOWN"; + }; + + return "UNKNOWN"; +} + +char * code_kernel_helpers_cleventToStr(int inst) +{ + switch(inst) + { + case CL_WRITEAT: + return "CL_WRITEAT"; + case CL_READAT: + return "CL_READAT"; + case CL_GETRANK: + return "CL_GETRANK"; + case CL_GETSIZE: + return "CL_GETSIZE"; + case CL_CLOSE: + return "CL_CLOSE"; + case CL_OPEN: + return "CL_OPEN"; + case CL_SYNC: + return "CL_SYNC"; + case CL_SLEEP: + return "CL_SLEEP"; + case CL_EXIT: + return "CL_EXIT"; + case CL_DELETE: + return "CL_DELETE"; + default: + return "CL_UNKNOWN"; + }; + + return "CL_UNKNOWN"; +} + +static int convertKLInstToEvent(int inst) +{ + switch(inst) + { + case WRITEAT: + return CL_WRITEAT; + case READAT: + return CL_READAT; + case GETGROUPRANK: + return CL_GETRANK; + case GETGROUPSIZE: + return CL_GETSIZE; + case CLOSE: + return CL_CLOSE; + case OPEN: + return CL_OPEN; + case SYNC: + return CL_SYNC; + case SLEEP: + return CL_SLEEP; + case EXIT: + return CL_EXIT; + case DELETE: + return CL_DELETE; + default: + return CL_UNKNOWN; + }; + + return CL_UNKNOWN; +} + +static void codes_kernel_helper_parse_cf(char * io_kernel_path, + char * io_kernel_meta_path, int task_rank, int max_ranks_default, + iolang_workload_info * task_info, int use_relpath) +{ + int foundit = 0; + char line[CK_LINE_LIMIT]; + FILE * ikmp = NULL; + + /* open the config file */ + ikmp = fopen(io_kernel_meta_path, "r"); + if(ikmp == NULL) + { + fprintf(stderr, "%s:%i could not open meta file (%s)... bail\n", __func__, + __LINE__, io_kernel_meta_path); + exit(1); + } + + /* for each line in the config file */ + while(fgets(line, CK_LINE_LIMIT, ikmp) != NULL) + { + char * token = NULL; + int min = 0; + int max = 0; + int gid = 0; + char * ctx = NULL; + + /* parse the first element... the gid */ + token = strtok_r(line, " \n", &ctx); + if(token) + gid = atoi(token); + + if(gid == CL_DEFAULT_GID) + { + fprintf(stderr, "%s:%i incorrect GID detected in kernel meta\ + file. Cannot use the reserved GID\ + CL_DEFAULT_GID(%i)\n", __func__, __LINE__, + CL_DEFAULT_GID); + } + + /* parse the second element... min rank */ + token = strtok_r(NULL, " \n", &ctx); + if(token) + min = atoi(token); + + /* parse the third element... max rank */ + token = strtok_r(NULL, " \n", &ctx); + if(token) + max = atoi(token); + + /* parse the last element... kernel path */ + token = strtok_r(NULL, " \n", &ctx); + if(token) { + if (use_relpath){ + /* posix dirname overwrites argument :(, need to + * prevent that */ + char *tmp_path = strdup(io_kernel_meta_path); + sprintf(io_kernel_path, "%s/%s", dirname(tmp_path), token); + free(tmp_path); + } + else{ + strcpy(io_kernel_path, token); + } + } + + /* if our rank is on this range... end processing of the config + * file */ + if(task_rank >= min && (max == -1 || task_rank <= max)) + { + task_info->group_id = gid; + task_info->min_rank = min; + task_info->max_rank = (max == -1) ? max_ranks_default : max; + task_info->local_rank = task_rank - min; + task_info->num_lrank = task_info->max_rank - min; + + foundit = 1; + + break; + } + } + + /* close the config file */ + fclose(ikmp); + + /* if we did not find the config file, set it to the default */ + if(foundit == 0) { + fprintf(stderr, + "ERROR: Unable to find iolang workload file " + "from given metadata file %s... exiting\n", + io_kernel_meta_path); + exit(1); + } + + return; +} + +int codes_kernel_helper_parse_input(CodesIOKernel_pstate * ps, CodesIOKernelContext * c, + codeslang_inst * inst) +{ + int yychar; + int status; + int codes_inst = CL_NOOP; + + /* swap in the symbol table for the current LP context */ + CodesIOKernelScannerSetSymTable(c); + + do + { + c->locval = CodesIOKernel_get_lloc(*((yyscan_t *)c->scanner_)); + yychar = CodesIOKernel_lex((codesYYType*)c->lval, (YYLTYPE*)c->locval, c->scanner_); + c->locval = NULL; + + /* for each instructions */ + switch(yychar) + { + /* for each instrunction that triggers a simulator event */ + case WRITEAT: + case READAT: + case GETGROUPRANK: + case GETGROUPSIZE: + case CLOSE: + case OPEN: + case SYNC: + case SLEEP: + case EXIT: + case DELETE: + { + c->inst_ready = 0; + status = CodesIOKernel_push_parse(ps, yychar, (codesYYType*)c->lval, (YYLTYPE*)c->locval, c); + codes_inst = convertKLInstToEvent(yychar); + break; + } + /* not a simulator event */ + default: + { + status = CodesIOKernel_push_parse(ps, yychar, (codesYYType*)c->lval, (YYLTYPE*)c->locval, c); + break; + } + }; + + /* if the instruction is ready (all preq data is ready ) */ + if(c->inst_ready) + { + /* reset instruction ready state */ + c->inst_ready = 0; + + switch(codes_inst) + { + case CL_GETRANK: + case CL_GETSIZE: + case CL_WRITEAT: + case CL_READAT: + case CL_OPEN: + case CL_CLOSE: + case CL_SYNC: + case CL_EXIT: + case CL_DELETE: + case CL_SLEEP: + { + int i = 0; + + inst->event_type = codes_inst; + inst->num_var = c->var[0]; + for(i = 0 ; i < inst->num_var ; i++) + { + inst->var[i] = c->var[i + 1]; + } + + break; + } + /* we don't need to store the instructions args */ + default: + { + continue; + } + }; + + /* we have all of the data for the instruction... bail */ + break; + } + /* while there are more instructions to parse in the stream */ + }while(status == YYPUSH_MORE); + + /* return the simulator instruction */ + return codes_inst; +} + +int codes_kernel_helper_bootstrap(char * io_kernel_path, + char * io_kernel_meta_path, int rank, int num_ranks, int use_relpath, + CodesIOKernelContext * c, CodesIOKernel_pstate ** ps, + iolang_workload_info * task_info, codeslang_inst * next_event) +{ + int t = CL_NOOP; + int ret = 0; + char * kbuffer = NULL; + int fd = 0; + off_t ksize = 0; + struct stat info; + + temp_group_rank = rank; + /* get the kernel from the file */ + codes_kernel_helper_parse_cf(io_kernel_path, + io_kernel_meta_path, rank, num_ranks, task_info, use_relpath); + temp_group_size = task_info->num_lrank; + /* stat the kernel file */ + ret = stat(io_kernel_path, &info); + if(ret != 0) + { + fprintf(stderr, "%s:%i could not stat kernel file (%s), exiting\n", + __func__, __LINE__, io_kernel_path); + perror("stat() error: "); + exit(1); + } + + /* get the size of the file */ + ksize = info.st_size; + + /* allocate a buffer for the kernel */ + kbuffer = (char *)malloc(sizeof(char) * (ksize+1)); + kbuffer[ksize] = '\0'; + + /* get data from the kernel file */ + fd = open(io_kernel_path, O_RDONLY); + ret = pread(fd, kbuffer, ksize, 0); + close(fd); + + /* init the scanner */ + CodesIOKernelScannerInit(c); + + if(ret <= ksize) + { + CodesIOKernel__scan_string(kbuffer, c->scanner_); + + *ps = CodesIOKernel_pstate_new(); + + /* get the first instruction */ + t = codes_kernel_helper_parse_input(*ps, c, next_event); + } + else + { + fprintf(stderr, "not enough buffer space... bail\n"); + exit(1); + } + + /* cleanup */ + free(kbuffer); + + return t; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/iokernellang/CodesKernelHelpers.h b/src/iokernellang/CodesKernelHelpers.h new file mode 100644 index 0000000000000000000000000000000000000000..542e0ac0757109067d6fbc3f670f98c91a11c8f7 --- /dev/null +++ b/src/iokernellang/CodesKernelHelpers.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#ifndef CODE_KERNEL_HELPERS_H +#define CODE_KERNEL_HELPERS_H + +#include +#include +#include + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 500 +#endif +#include + + +#include "CodesIOKernelTypes.h" +#include "CodesIOKernelParser.h" +#include "codeslexer.h" +#include "codes/codes-workload.h" + +#define CL_INST_MAX_ARGS 10 + +struct iolang_workload_info +{ + int group_id; /* group id */ + int min_rank; /* minimum rank in the collective operation */ + int max_rank; /* maximum rank in the collective operation */ + int local_rank; /* local rank? never being used in the bg/p model */ + int num_lrank; /* number of ranks participating in the collective operation*/ +}; + +typedef struct iolang_workload_info iolang_workload_info; + +enum cl_event_t +{ + CL_GETSIZE=1, + CL_GETRANK, + CL_WRITEAT, + CL_READAT, + CL_OPEN, + CL_CLOSE, + CL_SYNC, + CL_EXIT, + CL_NOOP, + CL_DELETE, + CL_SLEEP, + + /* last item should be an unknown inst */ + CL_UNKNOWN +}; + +typedef struct app_cf_info +{ + int gid; + int min; + int max; + int lrank; + int num_lrank; +} app_cf_info_t; + +typedef struct codeslang_inst +{ + int event_type; + int64_t num_var; + int64_t var[CL_INST_MAX_ARGS]; +} codeslang_inst; + +int codes_kernel_helper_parse_input(CodesIOKernel_pstate * ps, + CodesIOKernelContext * c, codeslang_inst * inst); + +int codes_kernel_helper_bootstrap(char * io_kernel_path, + char * io_kernel_meta_path, int rank, int num_ranks, int use_relpath, CodesIOKernelContext * c, + CodesIOKernel_pstate ** ps, iolang_workload_info * task_info, + codeslang_inst * next_event); + +char * code_kernel_helpers_cleventToStr(int inst); +char * code_kernel_helpers_kinstToStr(int inst); +#endif + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/iokernellang/codesImpl.c b/src/iokernellang/codesImpl.c new file mode 100644 index 0000000000000000000000000000000000000000..bd8c5991e2c72727ae832deea4110c3def827651 --- /dev/null +++ b/src/iokernellang/codesImpl.c @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include +#include +#include +#include "CodesIOKernelTypes.h" +#include "CodesIOKernelParser.h" + +int64_t ex( + nodeType * p) +{ + if(!p) + { + return 0; + } + + /* value or op switch */ + switch (p->type) + { + case typeCon: + { + return p->con.value; + } + case typeId: + { + return sym[p->id.i]; + } + case typeOpr: + { + /* op switch */ + switch (p->opr.oper) + { + case WHILE: + { + while(ex(p->opr.op[0])) + { + ex(p->opr.op[1]); + } + return 0; + } + case IF: + { + if(ex(p->opr.op[0])) + { + ex(p->opr.op[1]); + } + else if(p->opr.nops > 2) + { + ex(p->opr.op[2]); + } + return 0; + } + case PRINT: + { + printf("%"PRId64"\n", ex(p->opr.op[0])); + fflush(stdout); + return 0; + } + case WRITE_ALL: + { + int64_t t1 = ex(p->opr.op[0]); + int64_t t2 = ex(p->opr.op[1]); + + /* local storage of data used for the op */ + var[0] = 2; + var[1] = t1; + var[2] = t2; + *inst_ready = 1; + + return 0; + } + case WRITEAT_ALL: + { + int64_t t1 = ex(p->opr.op[0]); + int64_t t2 = ex(p->opr.op[1]); + int64_t t3 = ex(p->opr.op[2]); + + /* local storage of data used for the op */ + var[0] = 3; + var[1] = t1; + var[2] = t2; + var[3] = t3; + *inst_ready = 1; + + return 0; + } + case WRITE: + { + int64_t t1 = ex(p->opr.op[0]); + int64_t t2 = ex(p->opr.op[1]); + + /* local storage of data used for the op */ + var[0] = 2; + var[1] = t1; + var[2] = t2; + *inst_ready = 1; + + return 0; + } + case WRITEAT: + { + int64_t t1 = ex(p->opr.op[0]); + int64_t t2 = ex(p->opr.op[1]); + int64_t t3 = ex(p->opr.op[2]); + + /* local storage of data used for the op */ + var[0] = 3; + var[1] = t1; + var[2] = t2; + var[3] = t3; + *inst_ready = 1; + + return 0; + } + case READ_ALL: + { + int64_t t1 = ex(p->opr.op[0]); + int64_t t2 = ex(p->opr.op[1]); + + /* local storage of data used for the op */ + var[0] = 2; + var[1] = t1; + var[2] = t2; + *inst_ready = 1; + + return 0; + } + case READAT_ALL: + { + int64_t t1 = ex(p->opr.op[0]); + int64_t t2 = ex(p->opr.op[1]); + int64_t t3 = ex(p->opr.op[2]); + + /* local storage of data used for the op */ + var[0] = 3; + var[1] = t1; + var[2] = t2; + var[3] = t3; + *inst_ready = 1; + + return 0; + } + case READ: + { + int64_t t1 = ex(p->opr.op[0]); + int64_t t2 = ex(p->opr.op[1]); + + /* local storage of data used for the op */ + var[0] = 2; + var[1] = t1; + var[2] = t2; + *inst_ready = 1; + + return 0; + } + case READAT: + { + int64_t t1 = ex(p->opr.op[0]); + int64_t t2 = ex(p->opr.op[1]); + int64_t t3 = ex(p->opr.op[2]); + + /* local storage of data used for the op */ + var[0] = 3; + var[1] = t1; + var[2] = t2; + var[3] = t3; + *inst_ready = 1; + + return 0; + } + case SYNC: + { + int64_t t1 = ex(p->opr.op[0]); + + /* local storage of data used for the op */ + var[0] = 1; + var[1] = t1; + *inst_ready = 1; + + return 0; + } + case SLEEP: + { + int64_t t1 = ex(p->opr.op[0]); + + /* local storage of data used for the op */ + var[0] = 1; + var[1] = t1; + *inst_ready = 1; + + return 0; + } + case OPEN: + { + int64_t t1 = ex(p->opr.op[0]); + + /* local storage of data used for the op */ + var[0] = 1; + var[1] = t1; + *inst_ready = 1; + + return 0; + } + case CLOSE: + { + int64_t t1 = ex(p->opr.op[0]); + + /* local storage of data used for the op */ + var[0] = 1; + var[1] = t1; + *inst_ready = 1; + + return 0; + } + case DELETE: + { + int64_t t1 = ex(p->opr.op[0]); + + /* local storage of data used for the op */ + var[0] = 1; + var[1] = t1; + *inst_ready = 1; + + return 0; + } + case FLUSH: + { + int64_t t1 = ex(p->opr.op[0]); + + /* local storage of data used for the op */ + var[0] = 1; + var[1] = t1; + *inst_ready = 1; + + return 0; + } + case SEEK: + { + int64_t t1 = ex(p->opr.op[0]); + int64_t t2 = ex(p->opr.op[0]); + + /* local storage of data used for the op */ + var[0] = 1; + var[1] = t1; + var[2] = t2; + *inst_ready = 1; + + return 0; + } + case GETNUMGROUPS: + { + return 32; + } + case GETGROUPID: + { + return 8; + } + case EXIT: + { + int64_t t1 = ex(p->opr.op[0]); + var[0] = 1; + var[1] = t1; + *inst_ready = 1; + + return 4; + } + case GETGROUPRANK: + { + int64_t t1 = ex(p->opr.op[0]); + var[0] = 1; + var[1] = t1; + *inst_ready = 1; + + *group_rank = temp_group_rank; + //printf("\n group rank %d ", *group_rank); + return *group_rank; + } + case GETGROUPSIZE: + { + int64_t t1 = ex(p->opr.op[0]); + var[0] = 1; + var[1] = t1; + *inst_ready = 1; + /* JOHN - logic here is broken, using the same trick + * used to get the rank + * - should dynamically look up the group and rank, but + * sets it upon setting up the parser */ + /* *group_size = t1; */ + *group_size = temp_group_size; + + + //printf("\n group size %d ", *group_size); + return *group_size; + } + case GETCURTIME: + { + return 0; + } + case ';': + { + ex(p->opr.op[0]); + return ex(p->opr.op[1]); + } + case '=': + { + return sym[p->opr.op[0]->id.i] = ex(p->opr.op[1]); + } + case UMINUS: + { + return -ex(p->opr.op[0]); + } + case '+': + { + return ex(p->opr.op[0]) + ex(p->opr.op[1]); + } + case '-': + { + return ex(p->opr.op[0]) - ex(p->opr.op[1]); + } + case '*': + { + return ex(p->opr.op[0]) * ex(p->opr.op[1]); + } + case '/': + { + return ex(p->opr.op[0]) / ex(p->opr.op[1]); + } + case '%': + { + return ex(p->opr.op[0]) % ex(p->opr.op[1]); + } + case '<': + { + return ex(p->opr.op[0]) < ex(p->opr.op[1]); + } + case '>': + { + return ex(p->opr.op[0]) > ex(p->opr.op[1]); + } + case GE: + { + return ex(p->opr.op[0]) >= ex(p->opr.op[1]); + } + case LE: + { + return ex(p->opr.op[0]) <= ex(p->opr.op[1]); + } + case NE: + { + return ex(p->opr.op[0]) != ex(p->opr.op[1]); + } + case EQ: + { + return ex(p->opr.op[0]) == ex(p->opr.op[1]); + } + } + } + } + return 0; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/iokernellang/codeslexer.c b/src/iokernellang/codeslexer.c new file mode 100644 index 0000000000000000000000000000000000000000..3b27427d6e6b2a2cfbbc252d18988660c9c0a8a3 --- /dev/null +++ b/src/iokernellang/codeslexer.c @@ -0,0 +1,2327 @@ +#line 2 "codeslexer.c" + +#line 4 "codeslexer.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yyg->yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yyg->yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE CodesIOKernel_restart(yyin ,yyscanner ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires + * access to the local variable yy_act. Since yyless() is a macro, it would break + * existing scanners that call yyless() from OUTSIDE CodesIOKernel_lex. + * One obvious solution it to make yy_act a global. I tried that, and saw + * a 5% performance hit in a non-yylineno scanner, because yy_act is + * normally declared as a register variable-- so it is not worth it. + */ + #define YY_LESS_LINENO(n) \ + do { \ + int yyl;\ + for ( yyl = n; yyl < yyleng; ++yyl )\ + if ( yytext[yyl] == '\n' )\ + --yylineno;\ + }while(0) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = yyg->yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yyg->yytext_ptr , yyscanner ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via CodesIOKernel_restart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( yyg->yy_buffer_stack \ + ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] + +void CodesIOKernel_restart (FILE *input_file ,yyscan_t yyscanner ); +void CodesIOKernel__switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE CodesIOKernel__create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void CodesIOKernel__delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void CodesIOKernel__flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void CodesIOKernel_push_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void CodesIOKernel_pop_buffer_state (yyscan_t yyscanner ); + +static void CodesIOKernel_ensure_buffer_stack (yyscan_t yyscanner ); +static void CodesIOKernel__load_buffer_state (yyscan_t yyscanner ); +static void CodesIOKernel__init_buffer (YY_BUFFER_STATE b,FILE *file ,yyscan_t yyscanner ); + +#define YY_FLUSH_BUFFER CodesIOKernel__flush_buffer(YY_CURRENT_BUFFER ,yyscanner) + +YY_BUFFER_STATE CodesIOKernel__scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE CodesIOKernel__scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE CodesIOKernel__scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *CodesIOKernel_alloc (yy_size_t ,yyscan_t yyscanner ); +void *CodesIOKernel_realloc (void *,yy_size_t ,yyscan_t yyscanner ); +void CodesIOKernel_free (void * ,yyscan_t yyscanner ); + +#define yy_new_buffer CodesIOKernel__create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + CodesIOKernel_ensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + CodesIOKernel__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + CodesIOKernel_ensure_buffer_stack (yyscanner); \ + YY_CURRENT_BUFFER_LVALUE = \ + CodesIOKernel__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define CodesIOKernel_wrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +typedef int yy_state_type; + +#define yytext_ptr yytext_r + +static yy_state_type yy_get_previous_state (yyscan_t yyscanner ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner); +static int yy_get_next_buffer (yyscan_t yyscanner ); +static void yy_fatal_error (yyconst char msg[] ,yyscan_t yyscanner ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yyg->yytext_ptr = yy_bp; \ + yyleng = (size_t) (yy_cp - yy_bp); \ + yyg->yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yyg->yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 36 +#define YY_END_OF_BUFFER 37 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[134] = + { 0, + 0, 0, 37, 35, 34, 34, 35, 4, 2, 3, + 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 34, 8, 3, 6, 7, + 5, 0, 0, 0, 0, 0, 0, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 11, 33, 0, 0, 0, 0, 24, 0, + 17, 27, 0, 21, 0, 0, 25, 0, 26, 0, + 0, 0, 12, 0, 0, 23, 9, 13, 22, 0, + 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, + + 0, 0, 14, 0, 0, 0, 19, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 15, 0, 32, 28, + 0, 0, 0, 20, 0, 0, 0, 0, 16, 30, + 31, 29, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 1, 1, 1, 5, 1, 1, 5, + 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 1, 5, 8, + 9, 10, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 11, 1, 12, 13, 14, 15, + + 16, 17, 18, 19, 20, 13, 21, 22, 23, 24, + 25, 26, 13, 27, 28, 29, 30, 13, 31, 32, + 33, 34, 5, 1, 5, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[35] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1 + } ; + +static yyconst flex_int16_t yy_base[134] = + { 0, + 0, 0, 150, 151, 33, 35, 140, 151, 151, 33, + 139, 138, 137, 151, 123, 128, 19, 121, 126, 124, + 114, 112, 122, 26, 25, 43, 151, 43, 151, 151, + 151, 112, 114, 107, 114, 103, 103, 151, 115, 110, + 117, 112, 111, 102, 105, 104, 95, 106, 105, 91, + 91, 29, 94, 93, 101, 94, 98, 99, 90, 82, + 94, 80, 151, 151, 89, 77, 79, 75, 151, 75, + 43, 151, 77, 151, 86, 85, 151, 84, 151, 72, + 73, 74, 151, 84, 66, 151, 151, 45, 151, 65, + 63, 74, 69, 79, 77, 59, 67, 60, 58, 62, + + 71, 60, 70, 57, 38, 54, 151, 56, 55, 64, + 59, 59, 61, 52, 41, 48, 151, 47, 151, 151, + 44, 33, 38, 151, 41, 41, 45, 32, 151, 151, + 151, 151, 151 + } ; + +static yyconst flex_int16_t yy_def[134] = + { 0, + 133, 1, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 0 + } ; + +static yyconst flex_int16_t yy_nxt[186] = + { 0, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 4, 14, 14, 15, 16, 17, 18, 19, 14, 20, + 14, 14, 14, 14, 21, 22, 23, 24, 14, 14, + 25, 14, 14, 14, 26, 26, 26, 26, 28, 28, + 34, 42, 66, 45, 26, 26, 67, 43, 28, 28, + 35, 46, 68, 84, 85, 95, 96, 112, 44, 132, + 131, 130, 129, 128, 113, 114, 127, 126, 125, 124, + 123, 122, 121, 120, 119, 118, 117, 116, 115, 111, + 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, + 100, 99, 98, 97, 94, 93, 92, 91, 90, 89, + + 88, 87, 86, 83, 82, 81, 80, 79, 78, 77, + 76, 75, 74, 73, 72, 71, 70, 69, 65, 64, + 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, + 53, 52, 51, 50, 49, 48, 47, 41, 40, 39, + 38, 37, 36, 33, 32, 31, 30, 29, 27, 133, + 3, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133 + } ; + +static yyconst flex_int16_t yy_chk[186] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 5, 5, 6, 6, 10, 10, + 17, 24, 52, 25, 26, 26, 52, 24, 28, 28, + 17, 25, 52, 71, 71, 88, 88, 105, 24, 128, + 127, 126, 125, 123, 105, 105, 122, 121, 118, 116, + 115, 114, 113, 112, 111, 110, 109, 108, 106, 104, + 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, + 93, 92, 91, 90, 85, 84, 82, 81, 80, 78, + + 76, 75, 73, 70, 68, 67, 66, 65, 62, 61, + 60, 59, 58, 57, 56, 55, 54, 53, 51, 50, + 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, + 39, 37, 36, 35, 34, 33, 32, 23, 22, 21, + 20, 19, 18, 16, 15, 13, 12, 11, 7, 3, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + 133, 133, 133, 133, 133 + } ; + +/* Table of booleans, true if rule could match eol. */ +static yyconst flex_int32_t yy_rule_can_match_eol[37] = + { 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, }; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +#line 1 "codeslexer.l" +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ +#line 8 "codeslexer.l" +#include +#include "CodesIOKernelTypes.h" +#include "CodesIOKernelParser.h" + +#define YY_NO_INPUT + +#line 25 "codeslexer.l" + YYLTYPE *CodesIOKernel_get_lloc (yyscan_t yyscanner); + int CodesIOKernel_lex_init (yyscan_t* scanner); + int CodesIOKernel_lex(YYSTYPE * lvalp, YYLTYPE * llocp, void * scanner); + YY_BUFFER_STATE CodesIOKernel__scan_string (yyconst char *yy_str ,yyscan_t yyscanner); + + #define YY_EXTRA_TYPE CodesIOKernelContext* +#if 0 + #define YY_USER_ACTION \ + do { \ + yylloc->first_line = yylloc->last_line = 1; \ + yylloc->first_column = yylloc->last_column = 0; \ + } while(0) ; +#else + #define YY_USER_ACTION /* no user action */; +#endif + +#line 572 "codeslexer.c" + +#define INITIAL 0 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +/* Holds the entire state of the reentrant scanner. */ +struct yyguts_t + { + + /* User-defined. Not touched by flex. */ + YY_EXTRA_TYPE yyextra_r; + + /* The rest are the same as the globals declared in the non-reentrant scanner. */ + FILE *yyin_r, *yyout_r; + size_t yy_buffer_stack_top; /**< index of top of stack. */ + size_t yy_buffer_stack_max; /**< capacity of stack. */ + YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */ + char yy_hold_char; + int yy_n_chars; + int yyleng_r; + char *yy_c_buf_p; + int yy_init; + int yy_start; + int yy_did_buffer_switch_on_eof; + int yy_start_stack_ptr; + int yy_start_stack_depth; + int *yy_start_stack; + yy_state_type yy_last_accepting_state; + char* yy_last_accepting_cpos; + + int yylineno_r; + int yy_flex_debug_r; + + char *yytext_r; + int yy_more_flag; + int yy_more_len; + + YYSTYPE * yylval_r; + + YYLTYPE * yylloc_r; + + }; /* end struct yyguts_t */ + +static int yy_init_globals (yyscan_t yyscanner ); + + /* This must go here because YYSTYPE and YYLTYPE are included + * from bison output in section 1.*/ + # define yylval yyg->yylval_r + + # define yylloc yyg->yylloc_r + +int CodesIOKernel_lex_init (yyscan_t* scanner); + +int CodesIOKernel_lex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int CodesIOKernel_lex_destroy (yyscan_t yyscanner ); + +int CodesIOKernel_get_debug (yyscan_t yyscanner ); + +void CodesIOKernel_set_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE CodesIOKernel_get_extra (yyscan_t yyscanner ); + +void CodesIOKernel_set_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *CodesIOKernel_get_in (yyscan_t yyscanner ); + +void CodesIOKernel_set_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *CodesIOKernel_get_out (yyscan_t yyscanner ); + +void CodesIOKernel_set_out (FILE * out_str ,yyscan_t yyscanner ); + +int CodesIOKernel_get_leng (yyscan_t yyscanner ); + +char *CodesIOKernel_get_text (yyscan_t yyscanner ); + +int CodesIOKernel_get_lineno (yyscan_t yyscanner ); + +void CodesIOKernel_set_lineno (int line_number ,yyscan_t yyscanner ); + +YYSTYPE * CodesIOKernel_get_lval (yyscan_t yyscanner ); + +void CodesIOKernel_set_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + + YYLTYPE *CodesIOKernel_get_lloc (yyscan_t yyscanner ); + + void CodesIOKernel_set_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int CodesIOKernel_wrap (yyscan_t yyscanner ); +#else +extern int CodesIOKernel_wrap (yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (yyscan_t yyscanner ); +#else +static int input (yyscan_t yyscanner ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg , yyscanner) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int CodesIOKernel_lex \ + (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner); + +#define YY_DECL int CodesIOKernel_lex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + +#line 43 "codeslexer.l" + + +#line 819 "codeslexer.c" + + yylval = yylval_param; + + yylloc = yylloc_param; + + if ( !yyg->yy_init ) + { + yyg->yy_init = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yyg->yy_start ) + yyg->yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + CodesIOKernel_ensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + CodesIOKernel__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + CodesIOKernel__load_buffer_state(yyscanner ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yyg->yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yyg->yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yyg->yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 134 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 151 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) + { + int yyl; + for ( yyl = 0; yyl < yyleng; ++yyl ) + if ( yytext[yyl] == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + } + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yyg->yy_hold_char; + yy_cp = yyg->yy_last_accepting_cpos; + yy_current_state = yyg->yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 45 "codeslexer.l" +{ + if(yyextra->text != NULL) + { + free(yyextra->text); + } + yyextra->text = strdup(yytext); + yylval->sIndex = *(yyextra->text) - 'a'; + return VARIABLE; + } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 55 "codeslexer.l" +{ + if(yyextra->text != NULL) + { + free(yyextra->text); + } + yyextra->text = strdup(yytext); + yylval->iValue = atoi(yyextra->text); + return INTEGER; + } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 65 "codeslexer.l" +{ + if(yyextra->text != NULL) + { + free(yyextra->text); + } + yyextra->text = strdup(yytext); + yylval->iValue = atoll(yyextra->text); + return INTEGER; + } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 75 "codeslexer.l" +{ + if(yyextra->text != NULL) + { + free(yyextra->text); + } + yyextra->text = strdup(yytext); + return *(yyextra->text); + } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 84 "codeslexer.l" +return GE; + YY_BREAK +case 6: +YY_RULE_SETUP +#line 85 "codeslexer.l" +return LE; + YY_BREAK +case 7: +YY_RULE_SETUP +#line 86 "codeslexer.l" +return EQ; + YY_BREAK +case 8: +YY_RULE_SETUP +#line 87 "codeslexer.l" +return NE; + YY_BREAK +case 9: +YY_RULE_SETUP +#line 88 "codeslexer.l" +return WHILE; + YY_BREAK +case 10: +YY_RULE_SETUP +#line 89 "codeslexer.l" +return IF; + YY_BREAK +case 11: +YY_RULE_SETUP +#line 90 "codeslexer.l" +return ELSE; + YY_BREAK +case 12: +YY_RULE_SETUP +#line 91 "codeslexer.l" +return PRINT; + YY_BREAK +case 13: +YY_RULE_SETUP +#line 92 "codeslexer.l" +return WRITE; + YY_BREAK +case 14: +YY_RULE_SETUP +#line 93 "codeslexer.l" +return WRITEAT; + YY_BREAK +case 15: +YY_RULE_SETUP +#line 94 "codeslexer.l" +return WRITE_ALL; + YY_BREAK +case 16: +YY_RULE_SETUP +#line 95 "codeslexer.l" +return WRITEAT_ALL; + YY_BREAK +case 17: +YY_RULE_SETUP +#line 96 "codeslexer.l" +return READ; + YY_BREAK +case 18: +YY_RULE_SETUP +#line 97 "codeslexer.l" +return READAT; + YY_BREAK +case 19: +YY_RULE_SETUP +#line 98 "codeslexer.l" +return READ_ALL; + YY_BREAK +case 20: +YY_RULE_SETUP +#line 99 "codeslexer.l" +return READAT_ALL; + YY_BREAK +case 21: +YY_RULE_SETUP +#line 100 "codeslexer.l" +return SYNC; + YY_BREAK +case 22: +YY_RULE_SETUP +#line 101 "codeslexer.l" +return DELETE; + YY_BREAK +case 23: +YY_RULE_SETUP +#line 102 "codeslexer.l" +return SLEEP; + YY_BREAK +case 24: +YY_RULE_SETUP +#line 103 "codeslexer.l" +return OPEN; + YY_BREAK +case 25: +YY_RULE_SETUP +#line 104 "codeslexer.l" +return CLOSE; + YY_BREAK +case 26: +YY_RULE_SETUP +#line 105 "codeslexer.l" +return FLUSH; + YY_BREAK +case 27: +YY_RULE_SETUP +#line 106 "codeslexer.l" +return SEEK; + YY_BREAK +case 28: +YY_RULE_SETUP +#line 107 "codeslexer.l" +return GETGROUPID; + YY_BREAK +case 29: +YY_RULE_SETUP +#line 108 "codeslexer.l" +return GETNUMGROUPS; + YY_BREAK +case 30: +YY_RULE_SETUP +#line 109 "codeslexer.l" +return GETGROUPRANK; + YY_BREAK +case 31: +YY_RULE_SETUP +#line 110 "codeslexer.l" +return GETGROUPSIZE; + YY_BREAK +case 32: +YY_RULE_SETUP +#line 111 "codeslexer.l" +return GETCURTIME; + YY_BREAK +case 33: +YY_RULE_SETUP +#line 112 "codeslexer.l" +return EXIT; + YY_BREAK +case 34: +/* rule 34 can match eol */ +YY_RULE_SETUP +#line 114 "codeslexer.l" +; /* ignore whitespace */ + YY_BREAK +case 35: +YY_RULE_SETUP +#line 116 "codeslexer.l" +fprintf(stderr, "Unknown character\n"); + YY_BREAK +case 36: +YY_RULE_SETUP +#line 117 "codeslexer.l" +ECHO; + YY_BREAK +#line 1130 "codeslexer.c" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yyg->yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yyg->yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * CodesIOKernel_lex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yyg->yy_c_buf_p <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yyg->yy_c_buf_p = yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state , yyscanner); + + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yyg->yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yyg->yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_END_OF_FILE: + { + yyg->yy_did_buffer_switch_on_eof = 0; + + if ( CodesIOKernel_wrap(yyscanner ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yyg->yy_c_buf_p = yyg->yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = + yyg->yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yyg->yy_c_buf_p = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars]; + + yy_current_state = yy_get_previous_state( yyscanner ); + + yy_cp = yyg->yy_c_buf_p; + yy_bp = yyg->yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of CodesIOKernel_lex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = yyg->yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yyg->yy_c_buf_p > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yyg->yy_c_buf_p - yyg->yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yyg->yy_c_buf_p - yyg->yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) (yyg->yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + CodesIOKernel_realloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ,yyscanner ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + yyg->yy_n_chars, (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + if ( yyg->yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + CodesIOKernel_restart(yyin ,yyscanner); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) (yyg->yy_n_chars + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = yyg->yy_n_chars + number_to_move + (yyg->yy_n_chars >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) CodesIOKernel_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ,yyscanner ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + yyg->yy_n_chars += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yyg->yytext_ptr = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (yyscan_t yyscanner) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + yy_current_state = yyg->yy_start; + + for ( yy_cp = yyg->yytext_ptr + YY_MORE_ADJ; yy_cp < yyg->yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 134 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner) +{ + register int yy_is_jam; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */ + register char *yy_cp = yyg->yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yyg->yy_last_accepting_state = yy_current_state; + yyg->yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 134 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 133); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (yyscan_t yyscanner) +#else + static int input (yyscan_t yyscanner) +#endif + +{ + int c; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + *yyg->yy_c_buf_p = yyg->yy_hold_char; + + if ( *yyg->yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yyg->yy_c_buf_p < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars] ) + /* This was really a NUL. */ + *yyg->yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yyg->yy_c_buf_p - yyg->yytext_ptr; + ++yyg->yy_c_buf_p; + + switch ( yy_get_next_buffer( yyscanner ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + CodesIOKernel_restart(yyin ,yyscanner); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( CodesIOKernel_wrap(yyscanner ) ) + return EOF; + + if ( ! yyg->yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(yyscanner); +#else + return input(yyscanner); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yyg->yy_c_buf_p = yyg->yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yyg->yy_c_buf_p; /* cast for 8-bit char's */ + *yyg->yy_c_buf_p = '\0'; /* preserve yytext */ + yyg->yy_hold_char = *++yyg->yy_c_buf_p; + + if ( c == '\n' ) + + do{ yylineno++; + yycolumn=0; + }while(0) +; + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * @param yyscanner The scanner object. + * @note This function does not reset the start condition to @c INITIAL . + */ + void CodesIOKernel_restart (FILE * input_file , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! YY_CURRENT_BUFFER ){ + CodesIOKernel_ensure_buffer_stack (yyscanner); + YY_CURRENT_BUFFER_LVALUE = + CodesIOKernel__create_buffer(yyin,YY_BUF_SIZE ,yyscanner); + } + + CodesIOKernel__init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner); + CodesIOKernel__load_buffer_state(yyscanner ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * @param yyscanner The scanner object. + */ + void CodesIOKernel__switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* TODO. We should be able to replace this entire function body + * with + * CodesIOKernel_pop_buffer_state(); + * CodesIOKernel_push_buffer_state(new_buffer); + */ + CodesIOKernel_ensure_buffer_stack (yyscanner); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + CodesIOKernel__load_buffer_state(yyscanner ); + + /* We don't actually know whether we did this switch during + * EOF (CodesIOKernel_wrap()) processing, but the only time this flag + * is looked at is after CodesIOKernel_wrap() is called, so it's safe + * to go ahead and always set it. + */ + yyg->yy_did_buffer_switch_on_eof = 1; +} + +static void CodesIOKernel__load_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + yyg->yy_hold_char = *yyg->yy_c_buf_p; +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * @param yyscanner The scanner object. + * @return the allocated buffer state. + */ + YY_BUFFER_STATE CodesIOKernel__create_buffer (FILE * file, int size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) CodesIOKernel_alloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in CodesIOKernel__create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) CodesIOKernel_alloc(b->yy_buf_size + 2 ,yyscanner ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in CodesIOKernel__create_buffer()" ); + + b->yy_is_our_buffer = 1; + + CodesIOKernel__init_buffer(b,file ,yyscanner); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with CodesIOKernel__create_buffer() + * @param yyscanner The scanner object. + */ + void CodesIOKernel__delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + CodesIOKernel_free((void *) b->yy_ch_buf ,yyscanner ); + + CodesIOKernel_free((void *) b ,yyscanner ); +} + +#ifndef __cplusplus +extern int isatty (int ); +#endif /* __cplusplus */ + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a CodesIOKernel_restart() or at EOF. + */ + static void CodesIOKernel__init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner) + +{ + int oerrno = errno; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + CodesIOKernel__flush_buffer(b ,yyscanner); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then CodesIOKernel__init_buffer was _probably_ + * called from CodesIOKernel_restart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * @param yyscanner The scanner object. + */ + void CodesIOKernel__flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + CodesIOKernel__load_buffer_state(yyscanner ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * @param yyscanner The scanner object. + */ +void CodesIOKernel_push_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (new_buffer == NULL) + return; + + CodesIOKernel_ensure_buffer_stack(yyscanner); + + /* This block is copied from CodesIOKernel__switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *yyg->yy_c_buf_p = yyg->yy_hold_char; + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = yyg->yy_c_buf_p; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars; + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + yyg->yy_buffer_stack_top++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from CodesIOKernel__switch_to_buffer. */ + CodesIOKernel__load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * @param yyscanner The scanner object. + */ +void CodesIOKernel_pop_buffer_state (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + if (!YY_CURRENT_BUFFER) + return; + + CodesIOKernel__delete_buffer(YY_CURRENT_BUFFER ,yyscanner); + YY_CURRENT_BUFFER_LVALUE = NULL; + if (yyg->yy_buffer_stack_top > 0) + --yyg->yy_buffer_stack_top; + + if (YY_CURRENT_BUFFER) { + CodesIOKernel__load_buffer_state(yyscanner ); + yyg->yy_did_buffer_switch_on_eof = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void CodesIOKernel_ensure_buffer_stack (yyscan_t yyscanner) +{ + int num_to_alloc; + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (!yyg->yy_buffer_stack) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + yyg->yy_buffer_stack = (struct yy_buffer_state**)CodesIOKernel_alloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in CodesIOKernel_ensure_buffer_stack()" ); + + memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + yyg->yy_buffer_stack_max = num_to_alloc; + yyg->yy_buffer_stack_top = 0; + return; + } + + if (yyg->yy_buffer_stack_top >= (yyg->yy_buffer_stack_max) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = yyg->yy_buffer_stack_max + grow_size; + yyg->yy_buffer_stack = (struct yy_buffer_state**)CodesIOKernel_realloc + (yyg->yy_buffer_stack, + num_to_alloc * sizeof(struct yy_buffer_state*) + , yyscanner); + if ( ! yyg->yy_buffer_stack ) + YY_FATAL_ERROR( "out of dynamic memory in CodesIOKernel_ensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset(yyg->yy_buffer_stack + yyg->yy_buffer_stack_max, 0, grow_size * sizeof(struct yy_buffer_state*)); + yyg->yy_buffer_stack_max = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE CodesIOKernel__scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) CodesIOKernel_alloc(sizeof( struct yy_buffer_state ) ,yyscanner ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in CodesIOKernel__scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + CodesIOKernel__switch_to_buffer(b ,yyscanner ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to CodesIOKernel_lex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * CodesIOKernel__scan_bytes() instead. + */ +YY_BUFFER_STATE CodesIOKernel__scan_string (yyconst char * yystr , yyscan_t yyscanner) +{ + + return CodesIOKernel__scan_bytes(yystr,strlen(yystr) ,yyscanner); +} + +/** Setup the input buffer state to scan the given bytes. The next call to CodesIOKernel_lex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * @param yyscanner The scanner object. + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE CodesIOKernel__scan_bytes (yyconst char * yybytes, int _yybytes_len , yyscan_t yyscanner) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) CodesIOKernel_alloc(n ,yyscanner ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in CodesIOKernel__scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = CodesIOKernel__scan_buffer(buf,n ,yyscanner); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in CodesIOKernel__scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = yyg->yy_hold_char; \ + yyg->yy_c_buf_p = yytext + yyless_macro_arg; \ + yyg->yy_hold_char = *yyg->yy_c_buf_p; \ + *yyg->yy_c_buf_p = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the user-defined data for this scanner. + * @param yyscanner The scanner object. + */ +YY_EXTRA_TYPE CodesIOKernel_get_extra (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyextra; +} + +/** Get the current line number. + * @param yyscanner The scanner object. + */ +int CodesIOKernel_get_lineno (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yylineno; +} + +/** Get the current column number. + * @param yyscanner The scanner object. + */ +int CodesIOKernel_get_column (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + if (! YY_CURRENT_BUFFER) + return 0; + + return yycolumn; +} + +/** Get the input stream. + * @param yyscanner The scanner object. + */ +FILE *CodesIOKernel_get_in (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyin; +} + +/** Get the output stream. + * @param yyscanner The scanner object. + */ +FILE *CodesIOKernel_get_out (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyout; +} + +/** Get the length of the current token. + * @param yyscanner The scanner object. + */ +int CodesIOKernel_get_leng (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yyleng; +} + +/** Get the current token. + * @param yyscanner The scanner object. + */ + +char *CodesIOKernel_get_text (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yytext; +} + +/** Set the user-defined data. This data is never touched by the scanner. + * @param user_defined The data to be associated with this scanner. + * @param yyscanner The scanner object. + */ +void CodesIOKernel_set_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyextra = user_defined ; +} + +/** Set the current line number. + * @param line_number + * @param yyscanner The scanner object. + */ +void CodesIOKernel_set_lineno (int line_number , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* lineno is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "CodesIOKernel_set_lineno called with no buffer" , yyscanner); + + yylineno = line_number; +} + +/** Set the current column. + * @param line_number + * @param yyscanner The scanner object. + */ +void CodesIOKernel_set_column (int column_no , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* column is only valid if an input buffer exists. */ + if (! YY_CURRENT_BUFFER ) + yy_fatal_error( "CodesIOKernel_set_column called with no buffer" , yyscanner); + + yycolumn = column_no; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * @param yyscanner The scanner object. + * @see CodesIOKernel__switch_to_buffer + */ +void CodesIOKernel_set_in (FILE * in_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyin = in_str ; +} + +void CodesIOKernel_set_out (FILE * out_str , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yyout = out_str ; +} + +int CodesIOKernel_get_debug (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yy_flex_debug; +} + +void CodesIOKernel_set_debug (int bdebug , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yy_flex_debug = bdebug ; +} + +/* Accessor methods for yylval and yylloc */ + +YYSTYPE * CodesIOKernel_get_lval (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylval; +} + +void CodesIOKernel_set_lval (YYSTYPE * yylval_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylval = yylval_param; +} + +YYLTYPE *CodesIOKernel_get_lloc (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + return yylloc; +} + +void CodesIOKernel_set_lloc (YYLTYPE * yylloc_param , yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + yylloc = yylloc_param; +} + +/* User-visible API */ + +/* CodesIOKernel_lex_init is special because it creates the scanner itself, so it is + * the ONLY reentrant function that doesn't take the scanner as the last argument. + * That's why we explicitly handle the declaration, instead of using our macros. + */ + +int CodesIOKernel_lex_init(yyscan_t* ptr_yy_globals) + +{ + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) CodesIOKernel_alloc ( sizeof( struct yyguts_t ), NULL ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + return yy_init_globals ( *ptr_yy_globals ); +} + +/* CodesIOKernel_lex_init_extra has the same functionality as CodesIOKernel_lex_init, but follows the + * convention of taking the scanner as the last argument. Note however, that + * this is a *pointer* to a scanner, as it will be allocated by this call (and + * is the reason, too, why this function also must handle its own declaration). + * The user defined value in the first argument will be available to CodesIOKernel_alloc in + * the yyextra field. + */ + +int CodesIOKernel_lex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals ) + +{ + struct yyguts_t dummy_yyguts; + + CodesIOKernel_set_extra (yy_user_defined, &dummy_yyguts); + + if (ptr_yy_globals == NULL){ + errno = EINVAL; + return 1; + } + + *ptr_yy_globals = (yyscan_t) CodesIOKernel_alloc ( sizeof( struct yyguts_t ), &dummy_yyguts ); + + if (*ptr_yy_globals == NULL){ + errno = ENOMEM; + return 1; + } + + /* By setting to 0xAA, we expose bugs in + yy_init_globals. Leave at 0x00 for releases. */ + memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t)); + + CodesIOKernel_set_extra (yy_user_defined, *ptr_yy_globals); + + return yy_init_globals ( *ptr_yy_globals ); +} + +static int yy_init_globals (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from CodesIOKernel_lex_destroy(), so don't allocate here. + */ + + yyg->yy_buffer_stack = 0; + yyg->yy_buffer_stack_top = 0; + yyg->yy_buffer_stack_max = 0; + yyg->yy_c_buf_p = (char *) 0; + yyg->yy_init = 0; + yyg->yy_start = 0; + + yyg->yy_start_stack_ptr = 0; + yyg->yy_start_stack_depth = 0; + yyg->yy_start_stack = NULL; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = (FILE *) 0; + yyout = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * CodesIOKernel_lex_init() + */ + return 0; +} + +/* CodesIOKernel_lex_destroy is for both reentrant and non-reentrant scanners. */ +int CodesIOKernel_lex_destroy (yyscan_t yyscanner) +{ + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + CodesIOKernel__delete_buffer(YY_CURRENT_BUFFER ,yyscanner ); + YY_CURRENT_BUFFER_LVALUE = NULL; + CodesIOKernel_pop_buffer_state(yyscanner); + } + + /* Destroy the stack itself. */ + CodesIOKernel_free(yyg->yy_buffer_stack ,yyscanner); + yyg->yy_buffer_stack = NULL; + + /* Destroy the start condition stack. */ + CodesIOKernel_free(yyg->yy_start_stack ,yyscanner ); + yyg->yy_start_stack = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * CodesIOKernel_lex() is called, initialization will occur. */ + yy_init_globals( yyscanner); + + /* Destroy the main struct (reentrant only). */ + CodesIOKernel_free ( yyscanner , yyscanner ); + yyscanner = NULL; + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *CodesIOKernel_alloc (yy_size_t size , yyscan_t yyscanner) +{ + return (void *) malloc( size ); +} + +void *CodesIOKernel_realloc (void * ptr, yy_size_t size , yyscan_t yyscanner) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void CodesIOKernel_free (void * ptr , yyscan_t yyscanner) +{ + free( (char *) ptr ); /* see CodesIOKernel_realloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 117 "codeslexer.l" + + + +void CodesIOKernelScannerInit(CodesIOKernelContext * context) +{ + CodesIOKernel_lex_init(&context->scanner_); + CodesIOKernel_set_extra(context,context->scanner_); + context->text = NULL; + context->lval = malloc(sizeof(YYSTYPE)); + context->locval = CodesIOKernel_get_lloc(*(yyscan_t *)(context->scanner_)); + + //((YYLTYPE *)context->locval)->first_line = 1; + + int i = 0; + for(i = 0 ; i < 26 ; i++) + { + context->sym[i] = 0; + } + + for(i = 0 ; i < 10 ; i++) + { + context->next_var[i] = 0; + } + + for(i = 0 ; i < 10 ; i++) + { + context->var[i] = 0; + } + + context->inst_ready = 0; +} + +void CodesIOKernelScannerDestroy(CodesIOKernelContext * context) +{ + CodesIOKernel_lex_destroy(context->scanner_); + free(context->text); + context->text = NULL; + context->locval = NULL; + context->lval = NULL; +} + +void CodesIOKernelScannerSetSymTable(CodesIOKernelContext * context) +{ + sym = &(context->sym[0]); + var = &(context->var[0]); + inst_ready = &(context->inst_ready); + group_rank = &(context->GroupRank); + group_size = &(context->GroupSize); +} + diff --git a/src/iokernellang/codeslexer.h b/src/iokernellang/codeslexer.h new file mode 100644 index 0000000000000000000000000000000000000000..b571954e6ade2ae65e5c42b1348dbecdf3cb2fed --- /dev/null +++ b/src/iokernellang/codeslexer.h @@ -0,0 +1,359 @@ +#ifndef CodesIOKernel_HEADER_H +#define CodesIOKernel_HEADER_H 1 +#define CodesIOKernel_IN_HEADER 1 + +#line 6 "codeslexer.h" + +#line 8 "codeslexer.h" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +void CodesIOKernel_restart (FILE *input_file ,yyscan_t yyscanner ); +void CodesIOKernel__switch_to_buffer (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +YY_BUFFER_STATE CodesIOKernel__create_buffer (FILE *file,int size ,yyscan_t yyscanner ); +void CodesIOKernel__delete_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void CodesIOKernel__flush_buffer (YY_BUFFER_STATE b ,yyscan_t yyscanner ); +void CodesIOKernel_push_buffer_state (YY_BUFFER_STATE new_buffer ,yyscan_t yyscanner ); +void CodesIOKernel_pop_buffer_state (yyscan_t yyscanner ); + +YY_BUFFER_STATE CodesIOKernel__scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner ); +YY_BUFFER_STATE CodesIOKernel__scan_string (yyconst char *yy_str ,yyscan_t yyscanner ); +YY_BUFFER_STATE CodesIOKernel__scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner ); + +void *CodesIOKernel_alloc (yy_size_t ,yyscan_t yyscanner ); +void *CodesIOKernel_realloc (void *,yy_size_t ,yyscan_t yyscanner ); +void CodesIOKernel_free (void * ,yyscan_t yyscanner ); + +/* Begin user sect3 */ + +#define CodesIOKernel_wrap(n) 1 +#define YY_SKIP_YYWRAP + +#define yytext_ptr yytext_r + +#ifdef YY_HEADER_EXPORT_START_CONDITIONS +#define INITIAL 0 + +#endif + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +int CodesIOKernel_lex_init (yyscan_t* scanner); + +int CodesIOKernel_lex_init_extra (YY_EXTRA_TYPE user_defined,yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int CodesIOKernel_lex_destroy (yyscan_t yyscanner ); + +int CodesIOKernel_get_debug (yyscan_t yyscanner ); + +void CodesIOKernel_set_debug (int debug_flag ,yyscan_t yyscanner ); + +YY_EXTRA_TYPE CodesIOKernel_get_extra (yyscan_t yyscanner ); + +void CodesIOKernel_set_extra (YY_EXTRA_TYPE user_defined ,yyscan_t yyscanner ); + +FILE *CodesIOKernel_get_in (yyscan_t yyscanner ); + +void CodesIOKernel_set_in (FILE * in_str ,yyscan_t yyscanner ); + +FILE *CodesIOKernel_get_out (yyscan_t yyscanner ); + +void CodesIOKernel_set_out (FILE * out_str ,yyscan_t yyscanner ); + +int CodesIOKernel_get_leng (yyscan_t yyscanner ); + +char *CodesIOKernel_get_text (yyscan_t yyscanner ); + +int CodesIOKernel_get_lineno (yyscan_t yyscanner ); + +void CodesIOKernel_set_lineno (int line_number ,yyscan_t yyscanner ); + +YYSTYPE * CodesIOKernel_get_lval (yyscan_t yyscanner ); + +void CodesIOKernel_set_lval (YYSTYPE * yylval_param ,yyscan_t yyscanner ); + + YYLTYPE *CodesIOKernel_get_lloc (yyscan_t yyscanner ); + + void CodesIOKernel_set_lloc (YYLTYPE * yylloc_param ,yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int CodesIOKernel_wrap (yyscan_t yyscanner ); +#else +extern int CodesIOKernel_wrap (yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ,yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ,yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int CodesIOKernel_lex \ + (YYSTYPE * yylval_param,YYLTYPE * yylloc_param ,yyscan_t yyscanner); + +#define YY_DECL int CodesIOKernel_lex \ + (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +#undef YY_NEW_FILE +#undef YY_FLUSH_BUFFER +#undef yy_set_bol +#undef yy_new_buffer +#undef yy_set_interactive +#undef YY_DO_BEFORE_ACTION + +#ifdef YY_DECL_IS_OURS +#undef YY_DECL_IS_OURS +#undef YY_DECL +#endif + +#line 117 "codeslexer.l" + + +#line 358 "codeslexer.h" +#undef CodesIOKernel_IN_HEADER +#endif /* CodesIOKernel_HEADER_H */ diff --git a/src/iokernellang/codeslexer.l b/src/iokernellang/codeslexer.l new file mode 100644 index 0000000000000000000000000000000000000000..ba0e41a6565ca28bb90d3f48e11e1d47733ea709 --- /dev/null +++ b/src/iokernellang/codeslexer.l @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +%{ +#include +#include "src/iokernellang/CodesIOKernelTypes.h" +#include "src/iokernellang/CodesIOKernelParser.h" + +#define YY_NO_INPUT + +%} + +%option reentrant +%option prefix="CodesIOKernel_" +%option bison-bridge +%option bison-locations +%option noyywrap +%option yylineno +%option nounput + +%{ + YYLTYPE *CodesIOKernel_get_lloc (yyscan_t yyscanner); + int CodesIOKernel_lex_init (yyscan_t* scanner); + int CodesIOKernel_lex(YYSTYPE * lvalp, YYLTYPE * llocp, void * scanner); + YY_BUFFER_STATE CodesIOKernel__scan_string (yyconst char *yy_str ,yyscan_t yyscanner); + + #define YY_EXTRA_TYPE CodesIOKernelContext* +#if 0 + #define YY_USER_ACTION \ + do { \ + yylloc->first_line = yylloc->last_line = 1; \ + yylloc->first_column = yylloc->last_column = 0; \ + } while(0) ; +#else + #define YY_USER_ACTION /* no user action */; +#endif + +%} + +%% + +[a-z] { + if(yyextra->text != NULL) + { + free(yyextra->text); + } + yyextra->text = strdup(yytext); + yylval->sIndex = *(yyextra->text) - 'a'; + return VARIABLE; + } + +0 { + if(yyextra->text != NULL) + { + free(yyextra->text); + } + yyextra->text = strdup(yytext); + yylval->iValue = atoi(yyextra->text); + return INTEGER; + } + +[1-9][0-9]* { + if(yyextra->text != NULL) + { + free(yyextra->text); + } + yyextra->text = strdup(yytext); + yylval->iValue = atoll(yyextra->text); + return INTEGER; + } + +[-()<>=+*/%,;{}.] { + if(yyextra->text != NULL) + { + free(yyextra->text); + } + yyextra->text = strdup(yytext); + return *(yyextra->text); + } + +">=" return GE; +"<=" return LE; +"==" return EQ; +"!=" return NE; +"while" return WHILE; +"if" return IF; +"else" return ELSE; +"print" return PRINT; +"write" return WRITE; +"writeat" return WRITEAT; +"write_all" return WRITE_ALL; +"writeat_all" return WRITEAT_ALL; +"read" return READ; +"readat" return READAT; +"read_all" return READ_ALL; +"readat_all" return READAT_ALL; +"sync" return SYNC; +"delete" return DELETE; +"sleep" return SLEEP; +"open" return OPEN; +"close" return CLOSE; +"flush" return FLUSH; +"seek" return SEEK; +"getgroupid" return GETGROUPID; +"getnumgroups" return GETNUMGROUPS; +"getgrouprank" return GETGROUPRANK; +"getgroupsize" return GETGROUPSIZE; +"getcurtime" return GETCURTIME; +"exit" return EXIT; + +[ \t\n]+ ; /* ignore whitespace */ + +. fprintf(stderr, "Unknown character\n"); +%% + +void CodesIOKernelScannerInit(CodesIOKernelContext * context) +{ + yylex_init(&context->scanner_); + yyset_extra(context, context->scanner_); + context->text = NULL; + context->lval = malloc(sizeof(YYSTYPE)); + context->locval = CodesIOKernel_get_lloc(*(yyscan_t *)(context->scanner_)); + + //((YYLTYPE *)context->locval)->first_line = 1; + + int i = 0; + for(i = 0 ; i < 26 ; i++) + { + context->sym[i] = 0; + } + + for(i = 0 ; i < 10 ; i++) + { + context->next_var[i] = 0; + } + + for(i = 0 ; i < 10 ; i++) + { + context->var[i] = 0; + } + + context->inst_ready = 0; +} + +void CodesIOKernelScannerDestroy(CodesIOKernelContext * context) +{ + yylex_destroy(context->scanner_); + free(context->text); + context->text = NULL; + context->locval = NULL; + context->lval = NULL; +} + +void CodesIOKernelScannerSetSymTable(CodesIOKernelContext * context) +{ + sym = &(context->sym[0]); + var = &(context->var[0]); + inst_ready = &(context->inst_ready); + group_rank = &(context->GroupRank); + group_size = &(context->GroupSize); +} diff --git a/src/iokernellang/codesparser.c b/src/iokernellang/codesparser.c new file mode 100644 index 0000000000000000000000000000000000000000..cc7823c15ced7f2932e43b3d6a99c12cb41a3f48 --- /dev/null +++ b/src/iokernellang/codesparser.c @@ -0,0 +1,2504 @@ +/* A Bison parser, made by GNU Bison 2.5. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2011 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 3 of the License, 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.5" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 1 + +/* Pull parsers. */ +#define YYPULL 0 + +/* Using locations. */ +#define YYLSP_NEEDED 1 + +/* Substitute the variable and function names. */ +#define yypush_parse CodesIOKernel_push_parse +#define yypstate_new CodesIOKernel_pstate_new +#define yypstate_delete CodesIOKernel_pstate_delete +#define yypstate CodesIOKernel_pstate +#define yylex CodesIOKernel_lex +#define yyerror CodesIOKernel_error +#define yylval CodesIOKernel_lval +#define yychar CodesIOKernel_char +#define yydebug CodesIOKernel_debug +#define yynerrs CodesIOKernel_nerrs +#define yylloc CodesIOKernel_lloc + +/* Copy the first part of user declarations. */ + +/* Line 268 of yacc.c */ +#line 1 "codesparser.y" + +#include +#include +#include +#include +#include +#include "CodesIOKernelTypes.h" +#include "CodesIOKernelContext.h" + +/* prototypes */ +nodeType *opr(int64_t oper, int64_t nops, ...); +nodeType *id(int64_t i); +nodeType *con(int64_t value); +void freeNode(nodeType *p); +int64_t ex(nodeType *p); + +int64_t * sym = NULL; /* symbol table */ +int64_t * var = NULL; +int * inst_ready = NULL; +int * group_rank = NULL; +int * group_size = NULL; +int temp_group_rank = 0; +int temp_group_size = 0; + +/* Line 268 of yacc.c */ +#line 106 "codesparser.c" + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 1 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + INTEGER = 258, + VARIABLE = 259, + WHILE = 260, + IF = 261, + PRINT = 262, + WRITE = 263, + WRITEAT = 264, + WRITE_ALL = 265, + WRITEAT_ALL = 266, + READ = 267, + READAT = 268, + READ_ALL = 269, + READAT_ALL = 270, + SYNC = 271, + SLEEP = 272, + OPEN = 273, + CLOSE = 274, + DELETE = 275, + FLUSH = 276, + SEEK = 277, + EXIT = 278, + IFX = 279, + ELSE = 280, + NE = 281, + EQ = 282, + LE = 283, + GE = 284, + GETNUMGROUPS = 285, + GETGROUPID = 286, + GETCURTIME = 287, + GETGROUPSIZE = 288, + GETGROUPRANK = 289, + UMINUS = 290 + }; +#endif +/* Tokens. */ +#define INTEGER 258 +#define VARIABLE 259 +#define WHILE 260 +#define IF 261 +#define PRINT 262 +#define WRITE 263 +#define WRITEAT 264 +#define WRITE_ALL 265 +#define WRITEAT_ALL 266 +#define READ 267 +#define READAT 268 +#define READ_ALL 269 +#define READAT_ALL 270 +#define SYNC 271 +#define SLEEP 272 +#define OPEN 273 +#define CLOSE 274 +#define DELETE 275 +#define FLUSH 276 +#define SEEK 277 +#define EXIT 278 +#define IFX 279 +#define ELSE 280 +#define NE 281 +#define EQ 282 +#define LE 283 +#define GE 284 +#define GETNUMGROUPS 285 +#define GETGROUPID 286 +#define GETCURTIME 287 +#define GETGROUPSIZE 288 +#define GETGROUPRANK 289 +#define UMINUS 290 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 293 of yacc.c */ +#line 37 "codesparser.y" + + int64_t iValue; /* integer value */ + int64_t sIndex; /* symbol table index */ + nodeType *nPtr; /* node pointer */ + + + +/* Line 293 of yacc.c */ +#line 220 "codesparser.c" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + +#ifndef YYPUSH_DECLS +# define YYPUSH_DECLS +struct yypstate; +typedef struct yypstate yypstate; +enum { YYPUSH_MORE = 4 }; + +#if defined __STDC__ || defined __cplusplus +int yypush_parse (yypstate *yyps, int yypushed_char, YYSTYPE const *yypushed_val, YYLTYPE const *yypushed_loc, CodesIOKernelContext * context); +#else +int yypush_parse (); +#endif + +#if defined __STDC__ || defined __cplusplus +yypstate * yypstate_new (void); +#else +yypstate * yypstate_new (); +#endif +#if defined __STDC__ || defined __cplusplus +void yypstate_delete (yypstate *yyps); +#else +void yypstate_delete (); +#endif +#endif + + +/* Copy the second part of user declarations. */ + +/* Line 343 of yacc.c */ +#line 58 "codesparser.y" + + #include "CodesIOKernelContext.h" + + int CodesIOKernel_lex(YYSTYPE * lvalp, YYLTYPE * llocp, void * scanner); + + void CodesIOKernel_error(YYLTYPE * locp, CodesIOKernelContext * context, const char * err) + { + fprintf(stderr, "%i error = %s\n", locp->first_line, err); + } + + #define scanner context->scanner_ + + +/* Line 343 of yacc.c */ +#line 283 "codesparser.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ + && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; + YYLTYPE yyls_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 3 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 848 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 50 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 6 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 50 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 142 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 290 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 36, 2, 2, + 46, 47, 34, 32, 44, 33, 2, 35, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 43, + 27, 45, 26, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 48, 2, 49, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 28, 29, 30, 31, 37, 38, 39, 40, 41, + 42 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint8 yyprhs[] = +{ + 0, 0, 3, 5, 8, 9, 11, 14, 18, 22, + 28, 34, 42, 50, 56, 62, 70, 78, 82, 86, + 90, 94, 98, 102, 108, 113, 119, 125, 133, 137, + 139, 142, 144, 146, 149, 153, 157, 161, 165, 169, + 173, 177, 181, 185, 189, 193, 196, 199, 201, 203, + 205 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 51, 0, -1, 52, -1, 52, 53, -1, -1, 43, + -1, 55, 43, -1, 23, 55, 43, -1, 7, 55, + 43, -1, 8, 55, 44, 55, 43, -1, 10, 55, + 44, 55, 43, -1, 9, 55, 44, 55, 44, 55, + 43, -1, 11, 55, 44, 55, 44, 55, 43, -1, + 12, 55, 44, 55, 43, -1, 14, 55, 44, 55, + 43, -1, 13, 55, 44, 55, 44, 55, 43, -1, + 15, 55, 44, 55, 44, 55, 43, -1, 16, 55, + 43, -1, 17, 55, 43, -1, 18, 55, 43, -1, + 19, 55, 43, -1, 20, 55, 43, -1, 21, 55, + 43, -1, 22, 55, 44, 55, 43, -1, 4, 45, + 55, 43, -1, 5, 46, 55, 47, 53, -1, 6, + 46, 55, 47, 53, -1, 6, 46, 55, 47, 53, + 25, 53, -1, 48, 54, 49, -1, 53, -1, 54, + 53, -1, 3, -1, 4, -1, 33, 55, -1, 55, + 32, 55, -1, 55, 33, 55, -1, 55, 34, 55, + -1, 55, 35, 55, -1, 55, 36, 55, -1, 55, + 27, 55, -1, 55, 26, 55, -1, 55, 31, 55, + -1, 55, 30, 55, -1, 55, 28, 55, -1, 55, + 29, 55, -1, 41, 55, -1, 40, 55, -1, 39, + -1, 38, -1, 37, -1, 46, 55, 47, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint8 yyrline[] = +{ + 0, 74, 74, 78, 79, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 110, + 111, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "INTEGER", "VARIABLE", "WHILE", "IF", + "PRINT", "WRITE", "WRITEAT", "WRITE_ALL", "WRITEAT_ALL", "READ", + "READAT", "READ_ALL", "READAT_ALL", "SYNC", "SLEEP", "OPEN", "CLOSE", + "DELETE", "FLUSH", "SEEK", "EXIT", "IFX", "ELSE", "'>'", "'<'", "NE", + "EQ", "LE", "GE", "'+'", "'-'", "'*'", "'/'", "'%'", "GETNUMGROUPS", + "GETGROUPID", "GETCURTIME", "GETGROUPSIZE", "GETGROUPRANK", "UMINUS", + "';'", "','", "'='", "'('", "')'", "'{'", "'}'", "$accept", "program", + "function", "stmt", "stmt_list", "expr", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 62, 60, 281, 282, + 283, 284, 43, 45, 42, 47, 37, 285, 286, 287, + 288, 289, 290, 59, 44, 61, 40, 41, 123, 125 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 50, 51, 52, 52, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, + 54, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 2, 0, 1, 2, 3, 3, 5, + 5, 7, 7, 5, 5, 7, 7, 3, 3, 3, + 3, 3, 3, 5, 4, 5, 5, 7, 3, 1, + 2, 1, 1, 2, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 2, 2, 1, 1, 1, + 3 +}; + +/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 4, 0, 2, 1, 31, 32, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 49, 48, 47, 0, + 0, 5, 0, 0, 3, 0, 0, 0, 0, 32, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 33, 46, 45, + 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 0, 0, 0, 8, 0, + 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, + 20, 21, 22, 0, 7, 50, 28, 30, 40, 39, + 43, 44, 42, 41, 34, 35, 36, 37, 38, 24, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 25, 26, 9, 0, 10, 0, 13, 0, 14, + 0, 23, 0, 0, 0, 0, 0, 27, 11, 12, + 15, 16 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 1, 2, 34, 62, 35 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -26 +static const yytype_int16 yypact[] = +{ + -26, 19, 167, -26, -26, -25, -23, 2, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, -26, -26, -26, 64, + 64, -26, 64, 167, -26, 481, 64, 64, 64, -26, + 499, 234, 253, 272, 291, 310, 329, 348, 367, 517, + 535, 553, 571, 589, 607, 386, 625, -26, -26, -26, + 5, -26, 120, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, -26, 643, 190, 212, -26, 64, + 64, 64, 64, 64, 64, 64, 64, -26, -26, -26, + -26, -26, -26, 64, -26, -26, -26, -26, 10, 10, + 10, 10, 10, 10, -9, -9, -26, -26, -26, -26, + 167, 167, 661, 405, 679, 424, 697, 443, 715, 462, + 733, -26, 24, -26, 64, -26, 64, -26, 64, -26, + 64, -26, 167, 751, 769, 787, 805, -26, -26, -26, + -26, -26 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -26, -26, -26, -15, -26, -8 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = +{ + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 61, 3, + 36, 58, 59, 37, 60, 71, 72, 73, 75, 76, + 77, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 69, 70, 71, 72, 73, 97, 38, 132, + 0, 0, 95, 0, 0, 98, 99, 100, 101, 102, + 103, 104, 105, 106, 107, 108, 0, 4, 39, 0, + 0, 112, 113, 114, 115, 116, 117, 118, 119, 0, + 0, 0, 0, 0, 0, 120, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 121, 122, 25, 0, 0, + 0, 26, 27, 28, 29, 30, 0, 0, 0, 0, + 32, 0, 0, 0, 0, 0, 133, 137, 134, 0, + 135, 0, 136, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 25, 0, 0, 0, 26, 27, 28, + 29, 30, 0, 31, 0, 0, 32, 0, 33, 96, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 25, 0, 0, 0, 26, 27, 28, 29, 30, 0, + 31, 0, 0, 32, 0, 33, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 110, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 111, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 0, 0, 0, 0, 0, 0, 0, 79, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 0, 0, 0, 0, 0, 0, 0, 80, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 0, + 0, 0, 0, 0, 0, 0, 81, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 0, 0, + 0, 0, 0, 0, 0, 82, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 0, 0, 0, + 0, 0, 0, 0, 83, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 0, 0, 0, 0, + 0, 0, 0, 84, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 0, 0, 0, 0, 0, + 0, 0, 85, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 0, 0, 0, 0, 0, 0, + 0, 86, 63, 64, 65, 66, 67, 68, 69, 70, + 71, 72, 73, 0, 0, 0, 0, 0, 0, 0, + 93, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 0, 0, 0, 0, 0, 0, 0, 124, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, + 73, 0, 0, 0, 0, 0, 0, 0, 126, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 0, 0, 0, 0, 0, 0, 0, 128, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 0, + 0, 0, 0, 0, 0, 0, 130, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 0, 0, + 0, 0, 0, 0, 74, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 0, 0, 0, 0, + 0, 0, 78, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 0, 0, 0, 0, 0, 0, + 87, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 0, 0, 0, 0, 0, 0, 88, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 0, 0, 0, 0, 0, 0, 89, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 0, 0, + 0, 0, 0, 0, 90, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 0, 0, 0, 0, + 0, 0, 91, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 0, 0, 0, 0, 0, 0, + 92, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 0, 0, 0, 0, 0, 0, 94, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 0, 0, 0, 0, 0, 0, 109, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 0, 0, + 0, 0, 0, 0, 123, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 0, 0, 0, 0, + 0, 0, 125, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 0, 0, 0, 0, 0, 0, + 127, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 0, 0, 0, 0, 0, 0, 129, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 0, 0, 0, 0, 0, 0, 131, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 0, 0, + 0, 0, 0, 0, 138, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 0, 0, 0, 0, + 0, 0, 139, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 0, 0, 0, 0, 0, 0, + 140, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 0, 0, 0, 0, 0, 0, 141 +}; + +#define yypact_value_is_default(yystate) \ + ((yystate) == (-26)) + +#define yytable_value_is_error(yytable_value) \ + YYID (0) + +static const yytype_int16 yycheck[] = +{ + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 33, 0, + 45, 29, 30, 46, 32, 34, 35, 36, 36, 37, + 38, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 32, 33, 34, 35, 36, 62, 46, 25, + -1, -1, 47, -1, -1, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, -1, 3, 4, -1, + -1, 79, 80, 81, 82, 83, 84, 85, 86, -1, + -1, -1, -1, -1, -1, 93, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 110, 111, 33, -1, -1, + -1, 37, 38, 39, 40, 41, -1, -1, -1, -1, + 46, -1, -1, -1, -1, -1, 124, 132, 126, -1, + 128, -1, 130, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 33, -1, -1, -1, 37, 38, 39, + 40, 41, -1, 43, -1, -1, 46, -1, 48, 49, + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 33, -1, -1, -1, 37, 38, 39, 40, 41, -1, + 43, -1, -1, 46, -1, 48, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 47, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 47, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, -1, -1, -1, -1, -1, -1, -1, 44, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + -1, -1, -1, -1, -1, -1, -1, 44, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, + -1, -1, -1, -1, -1, -1, 44, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, + -1, -1, -1, -1, -1, 44, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, -1, -1, -1, + -1, -1, -1, -1, 44, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, -1, -1, -1, -1, + -1, -1, -1, 44, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, -1, -1, -1, -1, -1, + -1, -1, 44, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, -1, -1, -1, -1, -1, -1, + -1, 44, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, -1, -1, -1, -1, -1, -1, -1, + 44, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, -1, -1, -1, -1, -1, -1, -1, 44, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, -1, -1, -1, -1, -1, -1, -1, 44, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + -1, -1, -1, -1, -1, -1, -1, 44, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, 36, -1, + -1, -1, -1, -1, -1, -1, 44, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, + -1, -1, -1, -1, 43, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, -1, -1, -1, -1, + -1, -1, 43, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, -1, -1, -1, -1, -1, -1, + 43, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, -1, -1, -1, -1, -1, -1, 43, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + -1, -1, -1, -1, -1, -1, 43, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, + -1, -1, -1, -1, 43, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, -1, -1, -1, -1, + -1, -1, 43, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, -1, -1, -1, -1, -1, -1, + 43, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, -1, -1, -1, -1, -1, -1, 43, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + -1, -1, -1, -1, -1, -1, 43, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, + -1, -1, -1, -1, 43, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, -1, -1, -1, -1, + -1, -1, 43, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, -1, -1, -1, -1, -1, -1, + 43, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, -1, -1, -1, -1, -1, -1, 43, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + -1, -1, -1, -1, -1, -1, 43, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, -1, -1, + -1, -1, -1, -1, 43, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, -1, -1, -1, -1, + -1, -1, 43, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, -1, -1, -1, -1, -1, -1, + 43, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, -1, -1, -1, -1, -1, -1, 43 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 51, 52, 0, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 33, 37, 38, 39, 40, + 41, 43, 46, 48, 53, 55, 45, 46, 46, 4, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 53, 54, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 43, 55, 55, 55, 43, 44, + 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, + 43, 43, 43, 44, 43, 47, 49, 53, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 43, + 47, 47, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 53, 53, 43, 44, 43, 44, 43, 44, 43, + 44, 43, 25, 55, 55, 55, 55, 53, 43, 43, + 43, 43 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. However, + YYFAIL appears to be in use. Nevertheless, it is formally deprecated + in Bison 2.4.2's NEWS entry, where a plan to phase it out is + discussed. */ + +#define YYFAIL goto yyerrlab +#if defined YYFAIL + /* This is here to suppress warnings from the GCC cpp's + -Wunused-macros. Normally we don't worry about that warning, but + some users do, and we want to make it easy for users to remove + YYFAIL uses, which will produce warnings from Bison 2.5. */ +#endif + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (&yylloc, context, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval, &yylloc, scanner) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, Location, context); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, CodesIOKernelContext * context) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + CodesIOKernelContext * context; +#endif +{ + if (!yyvaluep) + return; + YYUSE (yylocationp); + YYUSE (context); +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, CodesIOKernelContext * context) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, context) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; + YYLTYPE const * const yylocationp; + CodesIOKernelContext * context; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + YY_LOCATION_PRINT (yyoutput, *yylocationp); + YYFPRINTF (yyoutput, ": "); + yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, context); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, CodesIOKernelContext * context) +#else +static void +yy_reduce_print (yyvsp, yylsp, yyrule, context) + YYSTYPE *yyvsp; + YYLTYPE *yylsp; + int yyrule; + CodesIOKernelContext * context; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , &(yylsp[(yyi + 1) - (yynrhs)]) , context); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, yylsp, Rule, context); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = 0; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - Assume YYFAIL is not used. It's too flawed to consider. See + + for details. YYERROR is fine as it does not invoke this + function. + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, CodesIOKernelContext * context) +#else +static void +yydestruct (yymsg, yytype, yyvaluep, yylocationp, context) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; + YYLTYPE *yylocationp; + CodesIOKernelContext * context; +#endif +{ + YYUSE (yyvaluep); + YYUSE (yylocationp); + YYUSE (context); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + +struct yypstate + { + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls; + YYLTYPE *yylsp; + + /* The locations where the error started and ended. */ + YYLTYPE yyerror_range[3]; + + YYSIZE_T yystacksize; + /* Used to determine if this is the first time this instance has + been used. */ + int yynew; + }; + +/* Initialize the parser data structure. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +yypstate * +yypstate_new (void) +#else +yypstate * +yypstate_new () + +#endif +{ + yypstate *yyps; + yyps = (yypstate *) malloc (sizeof *yyps); + if (!yyps) + return 0; + yyps->yynew = 1; + return yyps; +} + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void +yypstate_delete (yypstate *yyps) +#else +void +yypstate_delete (yyps) + yypstate *yyps; +#endif +{ +#ifndef yyoverflow + /* If the stack was reallocated but the parse did not complete, then the + stack still needs to be freed. */ + if (!yyps->yynew && yyps->yyss != yyps->yyssa) + YYSTACK_FREE (yyps->yyss); +#endif + free (yyps); +} + +#define CodesIOKernel_nerrs yyps->CodesIOKernel_nerrs +#define yystate yyps->yystate +#define yyerrstatus yyps->yyerrstatus +#define yyssa yyps->yyssa +#define yyss yyps->yyss +#define yyssp yyps->yyssp +#define yyvsa yyps->yyvsa +#define yyvs yyps->yyvs +#define yyvsp yyps->yyvsp +#define yylsa yyps->yylsa +#define yyls yyps->yyls +#define yylsp yyps->yylsp +#define yyerror_range yyps->yyerror_range +#define yystacksize yyps->yystacksize + + +/*---------------. +| yypush_parse. | +`---------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yypush_parse (yypstate *yyps, int yypushed_char, YYSTYPE const *yypushed_val, YYLTYPE const *yypushed_loc, CodesIOKernelContext * context) +#else +int +yypush_parse (yyps, yypushed_char, yypushed_val, yypushed_loc, context) + yypstate *yyps; + int yypushed_char; + YYSTYPE const *yypushed_val; + YYLTYPE const *yypushed_loc; + CodesIOKernelContext * context; +#endif +{ +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Location data for the lookahead symbol. */ +YYLTYPE yylloc; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + YYLTYPE yyloc; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + if (!yyps->yynew) + { + yyn = yypact[yystate]; + goto yyread_pushed_token; + } + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yyls = yylsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + yylsp = yyls; + +#if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL + /* Initialize the default location before parsing starts. */ + yylloc.first_line = yylloc.last_line = 1; + yylloc.first_column = yylloc.last_column = 1; +#endif + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + YYLTYPE *yyls1 = yyls; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + + yyls = yyls1; + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyls_alloc, yyls); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + yylsp = yyls + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + if (!yyps->yynew) + { + YYDPRINTF ((stderr, "Return for a new token:\n")); + yyresult = YYPUSH_MORE; + goto yypushreturn; + } + yyps->yynew = 0; +yyread_pushed_token: + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yypushed_char; + if (yypushed_val) + yylval = *yypushed_val; + if (yypushed_loc) + yylloc = *yypushed_loc; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + *++yylsp = yylloc; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + /* Default location. */ + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: + +/* Line 1806 of yacc.c */ +#line 74 "codesparser.y" + { /*exit(0)*/; } + break; + + case 3: + +/* Line 1806 of yacc.c */ +#line 78 "codesparser.y" + { ex((yyvsp[(2) - (2)].nPtr)); freeNode((yyvsp[(2) - (2)].nPtr)); } + break; + + case 5: + +/* Line 1806 of yacc.c */ +#line 83 "codesparser.y" + { (yyval.nPtr) = opr(';', 2, NULL, NULL); } + break; + + case 6: + +/* Line 1806 of yacc.c */ +#line 84 "codesparser.y" + { (yyval.nPtr) = (yyvsp[(1) - (2)].nPtr); } + break; + + case 7: + +/* Line 1806 of yacc.c */ +#line 85 "codesparser.y" + { (yyval.nPtr) = opr(EXIT, 1, (yyvsp[(2) - (3)].nPtr)); } + break; + + case 8: + +/* Line 1806 of yacc.c */ +#line 86 "codesparser.y" + { (yyval.nPtr) = opr(PRINT, 1, (yyvsp[(2) - (3)].nPtr)); } + break; + + case 9: + +/* Line 1806 of yacc.c */ +#line 87 "codesparser.y" + { (yyval.nPtr) = opr(WRITE, 2, (yyvsp[(2) - (5)].nPtr), (yyvsp[(4) - (5)].nPtr)); } + break; + + case 10: + +/* Line 1806 of yacc.c */ +#line 88 "codesparser.y" + { (yyval.nPtr) = opr(WRITE_ALL, 2, (yyvsp[(2) - (5)].nPtr), (yyvsp[(4) - (5)].nPtr)); } + break; + + case 11: + +/* Line 1806 of yacc.c */ +#line 89 "codesparser.y" + { (yyval.nPtr) = opr(WRITEAT, 3, (yyvsp[(2) - (7)].nPtr), (yyvsp[(4) - (7)].nPtr), (yyvsp[(6) - (7)].nPtr)); } + break; + + case 12: + +/* Line 1806 of yacc.c */ +#line 90 "codesparser.y" + { (yyval.nPtr) = opr(WRITEAT_ALL, 3, (yyvsp[(2) - (7)].nPtr), (yyvsp[(4) - (7)].nPtr), (yyvsp[(6) - (7)].nPtr)); } + break; + + case 13: + +/* Line 1806 of yacc.c */ +#line 91 "codesparser.y" + { (yyval.nPtr) = opr(READ, 2, (yyvsp[(2) - (5)].nPtr), (yyvsp[(4) - (5)].nPtr)); } + break; + + case 14: + +/* Line 1806 of yacc.c */ +#line 92 "codesparser.y" + { (yyval.nPtr) = opr(READ_ALL, 2, (yyvsp[(2) - (5)].nPtr), (yyvsp[(4) - (5)].nPtr)); } + break; + + case 15: + +/* Line 1806 of yacc.c */ +#line 93 "codesparser.y" + { (yyval.nPtr) = opr(READAT, 3, (yyvsp[(2) - (7)].nPtr), (yyvsp[(4) - (7)].nPtr), (yyvsp[(6) - (7)].nPtr) ); } + break; + + case 16: + +/* Line 1806 of yacc.c */ +#line 94 "codesparser.y" + { (yyval.nPtr) = opr(READAT_ALL, 3, (yyvsp[(2) - (7)].nPtr), (yyvsp[(4) - (7)].nPtr), (yyvsp[(6) - (7)].nPtr) ); } + break; + + case 17: + +/* Line 1806 of yacc.c */ +#line 95 "codesparser.y" + { (yyval.nPtr) = opr(SYNC, 1, (yyvsp[(2) - (3)].nPtr)); } + break; + + case 18: + +/* Line 1806 of yacc.c */ +#line 96 "codesparser.y" + { (yyval.nPtr) = opr(SLEEP, 1, (yyvsp[(2) - (3)].nPtr)); } + break; + + case 19: + +/* Line 1806 of yacc.c */ +#line 97 "codesparser.y" + { (yyval.nPtr) = opr(OPEN, 1, (yyvsp[(2) - (3)].nPtr)); } + break; + + case 20: + +/* Line 1806 of yacc.c */ +#line 98 "codesparser.y" + { (yyval.nPtr) = opr(CLOSE, 1, (yyvsp[(2) - (3)].nPtr)); } + break; + + case 21: + +/* Line 1806 of yacc.c */ +#line 99 "codesparser.y" + { (yyval.nPtr) = opr(DELETE, 1, (yyvsp[(2) - (3)].nPtr)); } + break; + + case 22: + +/* Line 1806 of yacc.c */ +#line 100 "codesparser.y" + { (yyval.nPtr) = opr(FLUSH, 1, (yyvsp[(2) - (3)].nPtr)); } + break; + + case 23: + +/* Line 1806 of yacc.c */ +#line 101 "codesparser.y" + { (yyval.nPtr) = opr(SEEK, 2, (yyvsp[(2) - (5)].nPtr), (yyvsp[(4) - (5)].nPtr)); } + break; + + case 24: + +/* Line 1806 of yacc.c */ +#line 102 "codesparser.y" + { (yyval.nPtr) = opr('=', 2, id((yyvsp[(1) - (4)].sIndex)), (yyvsp[(3) - (4)].nPtr)); } + break; + + case 25: + +/* Line 1806 of yacc.c */ +#line 103 "codesparser.y" + { (yyval.nPtr) = opr(WHILE, 2, (yyvsp[(3) - (5)].nPtr), (yyvsp[(5) - (5)].nPtr)); } + break; + + case 26: + +/* Line 1806 of yacc.c */ +#line 104 "codesparser.y" + { (yyval.nPtr) = opr(IF, 2, (yyvsp[(3) - (5)].nPtr), (yyvsp[(5) - (5)].nPtr)); } + break; + + case 27: + +/* Line 1806 of yacc.c */ +#line 105 "codesparser.y" + { (yyval.nPtr) = opr(IF, 3, (yyvsp[(3) - (7)].nPtr), (yyvsp[(5) - (7)].nPtr), (yyvsp[(7) - (7)].nPtr)); } + break; + + case 28: + +/* Line 1806 of yacc.c */ +#line 106 "codesparser.y" + { (yyval.nPtr) = (yyvsp[(2) - (3)].nPtr); } + break; + + case 29: + +/* Line 1806 of yacc.c */ +#line 110 "codesparser.y" + { (yyval.nPtr) = (yyvsp[(1) - (1)].nPtr); } + break; + + case 30: + +/* Line 1806 of yacc.c */ +#line 111 "codesparser.y" + { (yyval.nPtr) = opr(';', 2, (yyvsp[(1) - (2)].nPtr), (yyvsp[(2) - (2)].nPtr)); } + break; + + case 31: + +/* Line 1806 of yacc.c */ +#line 115 "codesparser.y" + { (yyval.nPtr) = con((yyvsp[(1) - (1)].iValue)); } + break; + + case 32: + +/* Line 1806 of yacc.c */ +#line 116 "codesparser.y" + { (yyval.nPtr) = id((yyvsp[(1) - (1)].sIndex)); } + break; + + case 33: + +/* Line 1806 of yacc.c */ +#line 117 "codesparser.y" + { (yyval.nPtr) = opr(UMINUS, 1, (yyvsp[(2) - (2)].nPtr)); } + break; + + case 34: + +/* Line 1806 of yacc.c */ +#line 118 "codesparser.y" + { (yyval.nPtr) = opr('+', 2, (yyvsp[(1) - (3)].nPtr), (yyvsp[(3) - (3)].nPtr)); } + break; + + case 35: + +/* Line 1806 of yacc.c */ +#line 119 "codesparser.y" + { (yyval.nPtr) = opr('-', 2, (yyvsp[(1) - (3)].nPtr), (yyvsp[(3) - (3)].nPtr)); } + break; + + case 36: + +/* Line 1806 of yacc.c */ +#line 120 "codesparser.y" + { (yyval.nPtr) = opr('*', 2, (yyvsp[(1) - (3)].nPtr), (yyvsp[(3) - (3)].nPtr)); } + break; + + case 37: + +/* Line 1806 of yacc.c */ +#line 121 "codesparser.y" + { (yyval.nPtr) = opr('/', 2, (yyvsp[(1) - (3)].nPtr), (yyvsp[(3) - (3)].nPtr)); } + break; + + case 38: + +/* Line 1806 of yacc.c */ +#line 122 "codesparser.y" + { (yyval.nPtr) = opr('%', 2, (yyvsp[(1) - (3)].nPtr), (yyvsp[(3) - (3)].nPtr)); } + break; + + case 39: + +/* Line 1806 of yacc.c */ +#line 123 "codesparser.y" + { (yyval.nPtr) = opr('<', 2, (yyvsp[(1) - (3)].nPtr), (yyvsp[(3) - (3)].nPtr)); } + break; + + case 40: + +/* Line 1806 of yacc.c */ +#line 124 "codesparser.y" + { (yyval.nPtr) = opr('>', 2, (yyvsp[(1) - (3)].nPtr), (yyvsp[(3) - (3)].nPtr)); } + break; + + case 41: + +/* Line 1806 of yacc.c */ +#line 125 "codesparser.y" + { (yyval.nPtr) = opr(GE, 2, (yyvsp[(1) - (3)].nPtr), (yyvsp[(3) - (3)].nPtr)); } + break; + + case 42: + +/* Line 1806 of yacc.c */ +#line 126 "codesparser.y" + { (yyval.nPtr) = opr(LE, 2, (yyvsp[(1) - (3)].nPtr), (yyvsp[(3) - (3)].nPtr)); } + break; + + case 43: + +/* Line 1806 of yacc.c */ +#line 127 "codesparser.y" + { (yyval.nPtr) = opr(NE, 2, (yyvsp[(1) - (3)].nPtr), (yyvsp[(3) - (3)].nPtr)); } + break; + + case 44: + +/* Line 1806 of yacc.c */ +#line 128 "codesparser.y" + { (yyval.nPtr) = opr(EQ, 2, (yyvsp[(1) - (3)].nPtr), (yyvsp[(3) - (3)].nPtr)); } + break; + + case 45: + +/* Line 1806 of yacc.c */ +#line 129 "codesparser.y" + { (yyval.nPtr) = opr(GETGROUPRANK, 1, (yyvsp[(2) - (2)].nPtr)); } + break; + + case 46: + +/* Line 1806 of yacc.c */ +#line 130 "codesparser.y" + { (yyval.nPtr) = opr(GETGROUPSIZE, 1, (yyvsp[(2) - (2)].nPtr)); } + break; + + case 47: + +/* Line 1806 of yacc.c */ +#line 131 "codesparser.y" + { (yyval.nPtr) = opr(GETCURTIME, 0); } + break; + + case 48: + +/* Line 1806 of yacc.c */ +#line 132 "codesparser.y" + { (yyval.nPtr) = opr(GETGROUPID, 0); } + break; + + case 49: + +/* Line 1806 of yacc.c */ +#line 133 "codesparser.y" + { (yyval.nPtr) = opr(GETNUMGROUPS, 0); } + break; + + case 50: + +/* Line 1806 of yacc.c */ +#line 134 "codesparser.y" + { (yyval.nPtr) = (yyvsp[(2) - (3)].nPtr); } + break; + + + +/* Line 1806 of yacc.c */ +#line 2173 "codesparser.c" + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + *++yylsp = yyloc; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (&yylloc, context, YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (&yylloc, context, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + yyerror_range[1] = yylloc; + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, &yylloc, context); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + yyerror_range[1] = yylsp[1-yylen]; + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + yyerror_range[1] = *yylsp; + yydestruct ("Error: popping", + yystos[yystate], yyvsp, yylsp, context); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + yyerror_range[2] = yylloc; + /* Using YYLLOC is tempting, but would change the location of + the lookahead. YYLOC is available though. */ + YYLLOC_DEFAULT (yyloc, yyerror_range, 2); + *++yylsp = yyloc; + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (&yylloc, context, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, &yylloc, context); + } + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, yylsp, context); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + yyps->yynew = 1; + +yypushreturn: +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + +/* Line 2067 of yacc.c */ +#line 137 "codesparser.y" + + +#define SIZEOF_NODETYPE ((char *)&p->con - (char *)p) + +nodeType * con(int64_t value) +{ + nodeType *p; + size_t nodeSize; + + /* allocate node */ + nodeSize = SIZEOF_NODETYPE + sizeof(conNodeType); + if((p = (nodeType*)malloc(nodeSize)) == NULL) + { + fprintf(stderr, "out of memory\n"); + } + + /* copy information */ + p->type = typeCon; + p->con.value = value; + + return p; +} + +nodeType * id(int64_t i) +{ + nodeType *p; + size_t nodeSize; + + /* allocate node */ + nodeSize = SIZEOF_NODETYPE + sizeof(idNodeType); + if((p = (nodeType*)malloc(nodeSize)) == NULL) + { + fprintf(stderr, "out of memory\n"); + } + + /* copy information */ + p->type = typeId; + p->id.i = i; + + return p; +} + +nodeType * opr(int64_t oper, int64_t nops, ...) +{ + va_list ap; + nodeType *p; + size_t nodeSize; + int64_t i; + + /* allocate node */ + nodeSize = SIZEOF_NODETYPE + sizeof(oprNodeType) + + (nops - 1) * sizeof(nodeType*); + + if ((p = (nodeType*)malloc(nodeSize)) == NULL) + { + fprintf(stderr, "out of memory\n"); + } + + /* copy information */ + p->type = typeOpr; + p->opr.oper = oper; + p->opr.nops = nops; + va_start(ap, nops); + for (i = 0; i < nops; i++) + { + p->opr.op[i] = va_arg(ap, nodeType*); + } + va_end(ap); + return p; +} + +void freeNode(nodeType *p) +{ + int64_t i; + + if (!p) + { + return; + } + + if(p->type == typeOpr) + { + for(i = 0; i < p->opr.nops; i++) + { + freeNode(p->opr.op[i]); + } + } + free(p); +} + diff --git a/src/iokernellang/codesparser.h b/src/iokernellang/codesparser.h new file mode 100644 index 0000000000000000000000000000000000000000..f11eb3402572aab92499591059b8544edb42f8b3 --- /dev/null +++ b/src/iokernellang/codesparser.h @@ -0,0 +1,173 @@ +/* A Bison parser, made by GNU Bison 2.5. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2011 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 3 of the License, 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + INTEGER = 258, + VARIABLE = 259, + WHILE = 260, + IF = 261, + PRINT = 262, + WRITE = 263, + WRITEAT = 264, + WRITE_ALL = 265, + WRITEAT_ALL = 266, + READ = 267, + READAT = 268, + READ_ALL = 269, + READAT_ALL = 270, + SYNC = 271, + SLEEP = 272, + OPEN = 273, + CLOSE = 274, + DELETE = 275, + FLUSH = 276, + SEEK = 277, + EXIT = 278, + IFX = 279, + ELSE = 280, + NE = 281, + EQ = 282, + LE = 283, + GE = 284, + GETNUMGROUPS = 285, + GETGROUPID = 286, + GETCURTIME = 287, + GETGROUPSIZE = 288, + GETGROUPRANK = 289, + UMINUS = 290 + }; +#endif +/* Tokens. */ +#define INTEGER 258 +#define VARIABLE 259 +#define WHILE 260 +#define IF 261 +#define PRINT 262 +#define WRITE 263 +#define WRITEAT 264 +#define WRITE_ALL 265 +#define WRITEAT_ALL 266 +#define READ 267 +#define READAT 268 +#define READ_ALL 269 +#define READAT_ALL 270 +#define SYNC 271 +#define SLEEP 272 +#define OPEN 273 +#define CLOSE 274 +#define DELETE 275 +#define FLUSH 276 +#define SEEK 277 +#define EXIT 278 +#define IFX 279 +#define ELSE 280 +#define NE 281 +#define EQ 282 +#define LE 283 +#define GE 284 +#define GETNUMGROUPS 285 +#define GETGROUPID 286 +#define GETCURTIME 287 +#define GETGROUPSIZE 288 +#define GETGROUPRANK 289 +#define UMINUS 290 + + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 2068 of yacc.c */ +#line 37 "codesparser.y" + + int64_t iValue; /* integer value */ + int64_t sIndex; /* symbol table index */ + nodeType *nPtr; /* node pointer */ + + + +/* Line 2068 of yacc.c */ +#line 128 "codesparser.h" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +} YYLTYPE; +# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + + +#ifndef YYPUSH_DECLS +# define YYPUSH_DECLS +struct CodesIOKernel_pstate; +typedef struct CodesIOKernel_pstate CodesIOKernel_pstate; +enum { YYPUSH_MORE = 4 }; +#if defined __STDC__ || defined __cplusplus +int CodesIOKernel_push_parse (CodesIOKernel_pstate *yyps, int yypushed_char, YYSTYPE const *yypushed_val, YYLTYPE const *yypushed_loc, CodesIOKernelContext * context); +#else +int CodesIOKernel_push_parse (); +#endif + +#if defined __STDC__ || defined __cplusplus +CodesIOKernel_pstate * CodesIOKernel_pstate_new (void); +#else +CodesIOKernel_pstate * CodesIOKernel_pstate_new (); +#endif +#if defined __STDC__ || defined __cplusplus +void CodesIOKernel_pstate_delete (CodesIOKernel_pstate *yyps); +#else +void CodesIOKernel_pstate_delete (); +#endif +#endif + diff --git a/src/iokernellang/codesparser.y.in b/src/iokernellang/codesparser.y.in new file mode 100644 index 0000000000000000000000000000000000000000..096f0b15ae9302cd93fb30b2dbcf73ef727f734d --- /dev/null +++ b/src/iokernellang/codesparser.y.in @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +%{ +#include +#include +#include +#include +#include +#include "src/iokernellang/CodesIOKernelTypes.h" +#include "src/iokernellang/CodesIOKernelContext.h" + +/* prototypes */ +nodeType *opr(int64_t oper, int64_t nops, ...); +nodeType *id(int64_t i); +nodeType *con(int64_t value); +void freeNode(nodeType *p); +int64_t ex(nodeType *p); + +int64_t * sym = NULL; /* symbol table */ +int64_t * var = NULL; +int * inst_ready = NULL; +int * group_rank = NULL; +int * group_size = NULL; + int temp_group_size = 0; + int temp_group_rank = 0; +%} + +/* start autogenerated code from CODES build system */ +@CODES_PURE_PARSER_DEFINES@ +@CODES_PUSH_PARSER_DEFINES@ +/* end autogenerated code from CODES build system */ + +%name-prefix="CodesIOKernel_" +%locations +%defines +%error-verbose + +%parse-param { CodesIOKernelContext * context } +%lex-param { void * scanner } + +%union { + int64_t iValue; /* integer value */ + int64_t sIndex; /* symbol table index */ + nodeType *nPtr; /* node pointer */ +}; + +%token INTEGER +%token VARIABLE +%token WHILE IF PRINT +%token WRITE WRITEAT WRITE_ALL WRITEAT_ALL READ READAT READ_ALL READAT_ALL SYNC SLEEP OPEN CLOSE DELETE FLUSH SEEK EXIT +%nonassoc IFX +%nonassoc ELSE + +%left GE LE EQ NE '>' '<' +%left '+' '-' +%left '*' '/' '%' +%left GETGROUPRANK GETGROUPSIZE GETCURTIME GETGROUPID GETNUMGROUPS +%nonassoc UMINUS + +%type stmt expr stmt_list + +%{ + #include "CodesIOKernelContext.h" + + int CodesIOKernel_lex(YYSTYPE * lvalp, YYLTYPE * llocp, void * scanner); + + void CodesIOKernel_error(YYLTYPE * locp, CodesIOKernelContext * context, const char * err) + { + fprintf(stderr, "%i error = %s\n", locp->first_line, err); + } + + #define scanner context->scanner_ +%} + +%% + +program: + function { /*exit(0)*/; } + ; + +function: + function stmt { ex($2); freeNode($2); } + | /* NULL */ + ; + +stmt: + ';' { $$ = opr(';', 2, NULL, NULL); } + | expr ';' { $$ = $1; } + | EXIT expr ';' { $$ = opr(EXIT, 1, $2); } + | PRINT expr ';' { $$ = opr(PRINT, 1, $2); } + | WRITE expr ',' expr ';' { $$ = opr(WRITE, 2, $2, $4); } + | WRITE_ALL expr ',' expr ';' { $$ = opr(WRITE_ALL, 2, $2, $4); } + | WRITEAT expr ',' expr ',' expr ';' { $$ = opr(WRITEAT, 3, $2, $4, $6); } + | WRITEAT_ALL expr ',' expr ',' expr ';' { $$ = opr(WRITEAT_ALL, 3, $2, $4, $6); } + | READ expr ',' expr ';' { $$ = opr(READ, 2, $2, $4); } + | READ_ALL expr ',' expr ';' { $$ = opr(READ_ALL, 2, $2, $4); } + | READAT expr ',' expr ',' expr ';' { $$ = opr(READAT, 3, $2, $4, $6 ); } + | READAT_ALL expr ',' expr ',' expr ';' { $$ = opr(READAT_ALL, 3, $2, $4, $6 ); } + | SYNC expr ';' { $$ = opr(SYNC, 1, $2); } + | SLEEP expr ';' { $$ = opr(SLEEP, 1, $2); } + | OPEN expr ';' { $$ = opr(OPEN, 1, $2); } + | CLOSE expr ';' { $$ = opr(CLOSE, 1, $2); } + | DELETE expr ';' { $$ = opr(DELETE, 1, $2); } + | FLUSH expr ';' { $$ = opr(FLUSH, 1, $2); } + | SEEK expr ',' expr ';' { $$ = opr(SEEK, 2, $2, $4); } + | VARIABLE '=' expr ';' { $$ = opr('=', 2, id($1), $3); } + | WHILE '(' expr ')' stmt { $$ = opr(WHILE, 2, $3, $5); } + | IF '(' expr ')' stmt %prec IFX { $$ = opr(IF, 2, $3, $5); } + | IF '(' expr ')' stmt ELSE stmt { $$ = opr(IF, 3, $3, $5, $7); } + | '{' stmt_list '}' { $$ = $2; } + ; + +stmt_list: + stmt { $$ = $1; } + | stmt_list stmt { $$ = opr(';', 2, $1, $2); } + ; + +expr: + INTEGER { $$ = con($1); } + | VARIABLE { $$ = id($1); } + | '-' expr %prec UMINUS { $$ = opr(UMINUS, 1, $2); } + | expr '+' expr { $$ = opr('+', 2, $1, $3); } + | expr '-' expr { $$ = opr('-', 2, $1, $3); } + | expr '*' expr { $$ = opr('*', 2, $1, $3); } + | expr '/' expr { $$ = opr('/', 2, $1, $3); } + | expr '%' expr { $$ = opr('%', 2, $1, $3); } + | expr '<' expr { $$ = opr('<', 2, $1, $3); } + | expr '>' expr { $$ = opr('>', 2, $1, $3); } + | expr GE expr { $$ = opr(GE, 2, $1, $3); } + | expr LE expr { $$ = opr(LE, 2, $1, $3); } + | expr NE expr { $$ = opr(NE, 2, $1, $3); } + | expr EQ expr { $$ = opr(EQ, 2, $1, $3); } + | GETGROUPRANK expr { $$ = opr(GETGROUPRANK, 1, $2); } + | GETGROUPSIZE expr { $$ = opr(GETGROUPSIZE, 1, $2); } + | GETCURTIME { $$ = opr(GETCURTIME, 0); } + | GETGROUPID { $$ = opr(GETGROUPID, 0); } + | GETNUMGROUPS { $$ = opr(GETNUMGROUPS, 0); } + | '(' expr ')' { $$ = $2; } + ; + +%% + +#define SIZEOF_NODETYPE ((char *)&p->con - (char *)p) + +nodeType * con(int64_t value) +{ + nodeType *p; + size_t nodeSize; + + /* allocate node */ + nodeSize = SIZEOF_NODETYPE + sizeof(conNodeType); + if((p = (nodeType*)malloc(nodeSize)) == NULL) + { + fprintf(stderr, "out of memory\n"); + } + + /* copy information */ + p->type = typeCon; + p->con.value = value; + + return p; +} + +nodeType * id(int64_t i) +{ + nodeType *p; + size_t nodeSize; + + /* allocate node */ + nodeSize = SIZEOF_NODETYPE + sizeof(idNodeType); + if((p = (nodeType*)malloc(nodeSize)) == NULL) + { + fprintf(stderr, "out of memory\n"); + } + + /* copy information */ + p->type = typeId; + p->id.i = i; + + return p; +} + +nodeType * opr(int64_t oper, int64_t nops, ...) +{ + va_list ap; + nodeType *p; + size_t nodeSize; + int64_t i; + + /* allocate node */ + nodeSize = SIZEOF_NODETYPE + sizeof(oprNodeType) + + (nops - 1) * sizeof(nodeType*); + + if ((p = (nodeType*)malloc(nodeSize)) == NULL) + { + fprintf(stderr, "out of memory\n"); + } + + /* copy information */ + p->type = typeOpr; + p->opr.oper = oper; + p->opr.nops = nops; + va_start(ap, nops); + for (i = 0; i < nops; i++) + { + p->opr.op[i] = va_arg(ap, nodeType*); + } + va_end(ap); + return p; +} + +void freeNode(nodeType *p) +{ + int64_t i; + + if (!p) + { + return; + } + + if(p->type == typeOpr) + { + for(i = 0; i < p->opr.nops; i++) + { + freeNode(p->opr.op[i]); + } + } + free(p); +} diff --git a/src/modelconfig/README.txt b/src/modelconfig/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..8a3ca5405edf981f285467da3636dd463b550d81 --- /dev/null +++ b/src/modelconfig/README.txt @@ -0,0 +1 @@ +The modelconfig code is based on the IOFSL server config tools diff --git a/src/modelconfig/configfile.c b/src/modelconfig/configfile.c new file mode 100644 index 0000000000000000000000000000000000000000..a923a7989db69fbfc77ec21e5e1e3efe740070bb --- /dev/null +++ b/src/modelconfig/configfile.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include "codes_base_config.h" +#include +#include +#include +#ifdef HAVE_MALLOC_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#include "configfile.h" +#include "txt_configfile.h" + +static int cf_equal_helper (struct ConfigVTable * h1, SectionHandle s1, struct ConfigVTable * h2, + SectionHandle s2) +{ + unsigned int sectionsize1; + unsigned int sectionsize2; + size_t count1; + size_t count2; + unsigned int i; + int ret = 1; + + cf_getSectionSize (h1, s1, §ionsize1); + cf_getSectionSize (h2, s2, §ionsize2); + + count1 = sectionsize1; + count2 = sectionsize2; + + if (count1 != count2) + return 0; + + SectionEntry entries1[sectionsize1]; + SectionEntry entries2[sectionsize2]; + + cf_listSection (h1, s1, &entries1[0], &count1); + cf_listSection (h2, s2, &entries2[0], &count2); + + for (i=0; i /* size_t */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * A config file is contains (possibly nested) sections, + * where each section groups entries. + * An entry is either another section, a key or a multikey. + * + * A key is a (name, value) string pair, while a multikey is a + * (name, value, value, value, ...) tuple. + */ +typedef void * SectionHandle; + + +enum { SE_SECTION = 1, + SE_KEY = 2, + SE_MULTIKEY = 3 + }; + +typedef struct +{ + char * name; + unsigned int type; +} SectionEntry; + +#define ROOT_SECTION ((SectionHandle) 0) + +struct ConfigVTable +{ + /* File path of the configuration file. Used in computing the relative path + * of file fields */ + char * config_dir; + + /* Returns number of characters in key or < 0 if an error occured + * (such as key is missing) + * + * Calling this function with a NULL buf ptr and 0 bufsize will + * return the keysize, not including terminating 0. + * + * */ + int (*getKey) (void * handle, SectionHandle section, const char * key, + char * buf, size_t bufsize); + + /* + * Reads list entries: after the function returns, buf will be set to + * a pointer pointing to an array of e char * pointers. + * Needs to be freed with free() (array + pointers) + * Returns < 0 if error */ + int (*getMultiKey) (void * handle, SectionHandle section, const char * key, + char *** buf, size_t * e); + /* + * Outputs number of entries written in maxentries, retrieves at most + * maxentries (input val). + * Returns total number of entries in section. + */ + int (*listSection) (void * handle, SectionHandle section, + SectionEntry * entries, size_t * maxentries); + + /* Returns -1 if failed, >=0 if ok */ + int (*openSection) (void * handle, SectionHandle section, const char * + sectionname, SectionHandle * newsection); + + /* Return the number of entries in a section in count, + * return code is <0 if error */ + int (*getSectionSize) (void * handle, SectionHandle section, unsigned int * + count); + + /* Returns < 0 if error */ + int (*closeSection) (void * handle, SectionHandle section); + + /* Returns < 0 if error */ + int (*createSection) (void * handle, SectionHandle section, const + char * name, SectionHandle * newsection); + + /* Returns < 0 if error */ + int (*createKey) (void * handle, SectionHandle section, const char * key, + const char ** data, unsigned int count); + + void (*free) (void * handle); + + void * data; + +}; + +/* utility debug function: write config tree to stdout; + * If all OK: ret >= 0, otherwise ret < 0 and *err is set + * to error message + * */ +int cf_dump (struct ConfigVTable * cf, SectionHandle h, char ** err); + +/* Compare two config trees: return true if equal, false if not */ +int cf_equal (struct ConfigVTable * h1, struct ConfigVTable * h2); + +static inline int cf_free (struct ConfigVTable * cf) +{ + if (!cf) + return 1; + + cf->free (cf->data); + free (cf); + return 1; +} + +static inline int cf_getSectionSize (struct ConfigVTable * cf, SectionHandle section, + unsigned int * count) +{ + return cf->getSectionSize (cf->data, section, count); +} + +static inline int cf_closeSection (struct ConfigVTable * cf, SectionHandle section) +{ + return cf->closeSection (cf->data, section); +} + +static inline int cf_openSection (struct ConfigVTable * cf, SectionHandle section, + const char * sectionname, SectionHandle * newsection) +{ + return cf->openSection (cf->data, section, sectionname, newsection); +} + +static inline int cf_getKey (struct ConfigVTable * cf, SectionHandle section, + const char * keyname, char * buf, size_t maxbuf) +{ + return cf->getKey (cf->data, section, keyname, buf, maxbuf); +} + +static inline int cf_getMultiKey (struct ConfigVTable * cf, SectionHandle section, + const char * keyname, char *** buf, size_t * e) +{ + return cf->getMultiKey (cf->data, section, keyname, buf, e); +} + +static inline int cf_listSection (struct ConfigVTable * cf, SectionHandle section, + SectionEntry * entries, size_t * maxentries) +{ + return cf->listSection (cf->data, section, entries, maxentries); +} + +static inline int cf_createSection (struct ConfigVTable * handle, SectionHandle + section, const char * name, SectionHandle * newsection) +{ + return handle->createSection (handle->data, section, name, + newsection); +} + +static inline int cf_createKey (struct ConfigVTable * handle, SectionHandle section, + const char * key, const char ** data, unsigned int count) +{ + return handle->createKey (handle->data, section, key, data, count); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/modelconfig/configglue.c b/src/modelconfig/configglue.c new file mode 100644 index 0000000000000000000000000000000000000000..9778ea11b03736e08b2b48d497eefa6e95031abe --- /dev/null +++ b/src/modelconfig/configglue.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include +#include +#include +#include "configglue.h" + +int cfgp_lex_error (ParserParams * p, int lineno, int colno, const char * msg) +{ + char buf[512]; + snprintf (buf, sizeof(buf), "lexer error (line %i, column %i): %s", lineno, + colno, msg); + p->lexer_error_string = strdup (buf); + p->lexer_error_code = 2; + return -1; +} + +int cfgp_parser_error(ParserParams * p, const char * err, + unsigned int first_line, unsigned int first_column, + unsigned int last_line, unsigned int last_column) +{ + char location[128]; + char buf[512]; + + if (first_line) + { + snprintf (location, sizeof(location), "%i:%i until %i:%i", + first_line, first_column, last_line, last_column); + } + else if (last_line) + { + snprintf (location, sizeof(location), "line %i, column %i", + last_line, last_column); + } + else + { + strcpy (buf, "unknown location"); + } + + snprintf (buf, sizeof(buf), "Parser error (%s): %s", location, err); + p->parser_error_code =1; + p->parser_error_string = strdup (buf); + return -1; +} + +void cfgp_initparams (ParserParams * p, struct ConfigVTable * h) +{ + p->configfile = h; + p->stacktop = 0; + p->sectionstack[0] = 0; + p->parser_error_code = 0; + p->parser_error_string = 0; + p->lexer_error_code=0; + p->lexer_error_string=0; +} + +void cfgp_freeparams (ParserParams * p) +{ + free (p->lexer_error_string); + free (p->parser_error_string); +} + +int cfgp_parse_ok (const ParserParams * p, char * buf, int bufsize) +{ + /* doublecheck that if an error string is present, the error code is also + * set */ + assert(!p->lexer_error_string || p->lexer_error_code); + assert(!p->parser_error_string || p->parser_error_code); + + if (p->lexer_error_code) + { + strncpy (buf, p->lexer_error_string, bufsize); + return 0; + } + if (p->parser_error_code) + { + strncpy (buf, p->parser_error_string, bufsize); + return 0; + } + return 1; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/modelconfig/configglue.h b/src/modelconfig/configglue.h new file mode 100644 index 0000000000000000000000000000000000000000..7d88155b653799e1bc47190b8109dea9bbe5d211 --- /dev/null +++ b/src/modelconfig/configglue.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#ifndef SRC_COMMON_MODELCONFIG_CONFIGGLUE_H +#define SRC_COMMON_MODELCONFIG_CONFIGGLUE_H + +/* Common header for parser and lexer */ + +#include "configfile.h" + + +typedef struct +{ + struct ConfigVTable * configfile; + + SectionHandle sectionstack [20]; + unsigned int stacktop; + + /* used to construct a multival key */ + struct + { + char ** keyvals; + unsigned int count; + unsigned int maxsize; + }; + + int parser_error_code; + + /* if error_code != 0 the user needs to free error_string */ + char * parser_error_string; + int lexer_error_code; + char * lexer_error_string; +} ParserParams; + +void cfgp_initparams (ParserParams * p, struct ConfigVTable * h); + +/* Free private data (but not the ConfigVTable) */ +void cfgp_freeparams (ParserParams * p); + +int cfgp_parser_error (ParserParams * p, const char* str, + unsigned int l1, unsigned int c1, unsigned int l2, unsigned int c2); + +int cfgp_lex_error (ParserParams * p, int lineno, int colno, const char * msg); + +/* Return true if parse and lex went ok; false otherwise, and puts + * error message in buf. Note: ConfigVTable might still contain the partial + * parsed tree */ +int cfgp_parse_ok (const ParserParams * p, char * buf, int bufsize); + +#endif + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/modelconfig/configlex.l b/src/modelconfig/configlex.l new file mode 100644 index 0000000000000000000000000000000000000000..ef47f32b85ae2d84c75e8891c5552935819b7e38 --- /dev/null +++ b/src/modelconfig/configlex.l @@ -0,0 +1,243 @@ +%{ + +#include +#include "src/modelconfig/configglue.h" +#include "src/modelconfig/configparser.h" + +#define YY_EXTRA_TYPE ParserParams * + +/* Disable warnings in the flex generated code */ +#if defined __GNUC__ +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wsign-compare" +#elif defined __SUNPRO_CC +#pragma disable_warn +#elif defined _MSC_VER +#pragma warning(push, 1) +#endif + +#define CFGP_CHECKOVERFLOW + +#define LOC_COL_ADV(a) yylloc->last_column+=(a) +#define LOC_COL_DEF_ADV yylloc->last_column+=strlen(yytext) +#define LOC_COL_RESET yylloc->last_column=1 +#define LOC_LINE_ADV(a) yylloc->last_line+=(a),yylloc->last_column=1 +#define LOC_RESET_FIRST yylloc->first_line=yylloc->first_column=0 +#define LOC_INIT_FIRST yylloc->first_line=yylloc->last_line,\ + yylloc->first_column=yylloc->last_column + +#define LOC_INIT_LAST yylloc->last_line=1,yylloc->last_column=1 + +#define YY_USER_INIT LOC_INIT_LAST,LOC_INIT_FIRST; \ + yyextra->lexer_error_code=0; yyextra->lexer_error_string=0; + +%} + + +%option reentrant stack noyywrap bison-locations +%x COMMENT STRING_LITERAL COMMENT2 +%option prefix="cfgp_" +%option bison-bridge nodefault + +DIGIT [0-9] +ID [a-zA-Z][a-zA-Z0-9_\-]*(@[a-zA-Z0-9_\-]+)? + +SECTION_OPEN "{" +SECTION_CLOSE "}" +SEMICOLUMN ";" +BACKSLASH "\\" + +%% + +"/*" { + LOC_COL_DEF_ADV; + LOC_INIT_FIRST; + /* ignore comments */ + yy_push_state(COMMENT2, yyscanner); + } + +"*/" { + /* ignore comments */ + LOC_RESET_FIRST; + yy_pop_state (yyscanner); + } + +\n { LOC_LINE_ADV(1); } + +.+ { + LOC_COL_DEF_ADV; + /* ignore comments */ + } + +<> { + char buf[512]; + snprintf (buf,sizeof(buf), + "Unterminated /* (started at line %i, column %i)", + yylloc->first_line, yylloc->first_column); + + return cfgp_lex_error (yyextra, + yylloc->last_line,yylloc->last_column, buf); + } + +"//" { LOC_COL_ADV(1); yy_push_state(COMMENT, yyscanner); } +"#" { LOC_COL_ADV(1); yy_push_state(COMMENT, yyscanner); } + +\n { LOC_LINE_ADV(1); yy_pop_state( yyscanner ); } +[^\n]+ { LOC_COL_DEF_ADV; } + +\" { + LOC_COL_DEF_ADV; + LOC_INIT_FIRST; + yylval->curstringpos = 0; + yy_push_state(STRING_LITERAL, yyscanner); + } + + +\" { + /* saw closing quote - all done */ + LOC_COL_DEF_ADV; + LOC_RESET_FIRST; + yy_pop_state(yyscanner); + CFGP_CHECKOVERFLOW; + yylval->string_buf[yylval->curstringpos] = '\0'; + /* return string constant token type and + * value to parser + */ + return LITERAL_STRING; + } + +\n { + char buf[512]; + snprintf (buf, sizeof(buf), + "Unterminated string constant (started at line %i, column" + " %i)!", yylloc->first_line, yylloc->first_column); + return cfgp_lex_error (yyextra, yylloc->last_line, yylloc->last_column, + buf); + } + +\\[0-7]{1,3} { + /* octal escape sequence */ + LOC_COL_DEF_ADV; + int result; + + (void) sscanf( yytext + 1, "%o", &result ); + + if ( result > 0xff ) + { + /* error, constant is out-of-bounds */ + return cfgp_lex_error (yyextra, yylloc->last_line, yylloc->last_column, + "Out of bounds \\0xx escape in string!"); + } + + yylval->string_buf[yylval->curstringpos++] = result; + CFGP_CHECKOVERFLOW; + } + +\\[0-9]+ { + /* generate error - bad escape sequence; something + * like '\48' or '\0777777' + */ + return cfgp_lex_error (yyextra, + yylloc->last_line, yylloc->last_column, + "Bad \\xxxx escape in string!"); + } + +\\n { LOC_COL_DEF_ADV; yylval->string_buf[yylval->curstringpos++] = '\n'; CFGP_CHECKOVERFLOW; } +\\t { LOC_COL_DEF_ADV; yylval->string_buf[yylval->curstringpos++] = '\t'; CFGP_CHECKOVERFLOW; } +\\r { LOC_COL_DEF_ADV; yylval->string_buf[yylval->curstringpos++] = '\r'; CFGP_CHECKOVERFLOW; } +\\b { LOC_COL_DEF_ADV; yylval->string_buf[yylval->curstringpos++] = '\b'; CFGP_CHECKOVERFLOW; } +\\f { LOC_COL_DEF_ADV; yylval->string_buf[yylval->curstringpos++] = '\f'; CFGP_CHECKOVERFLOW; } + +\\\n { + LOC_LINE_ADV(1); + yylval->string_buf[yylval->curstringpos++] = yytext[1]; + CFGP_CHECKOVERFLOW; + } + +\\. { + LOC_COL_DEF_ADV; + yylval->string_buf[yylval->curstringpos++] = yytext[1]; + CFGP_CHECKOVERFLOW; + } + +[^\\\n\"]+ { + char *yptr = yytext; + + LOC_COL_DEF_ADV; + + while ( *yptr ) + { + yylval->string_buf[yylval->curstringpos++] = *yptr++; + CFGP_CHECKOVERFLOW; + } + } + +\\ { + /* a single slash at the end of the input */ + char buf[512]; + snprintf (buf, sizeof(buf), "Unterminated string constant " + "(started at line %i, column %i)!", yylloc->first_line, + yylloc->first_column); + + return cfgp_lex_error (yyextra, + yylloc->last_line, yylloc->last_column, buf); + } + +{ID} { + LOC_COL_DEF_ADV; + if (strlen (yytext) >= sizeof(yylval->string_buf)) + { + char buf[512]; + snprintf (buf, sizeof(buf), "ID too long: Maximum ID" + " length is %lu bytes!", sizeof(yylval->string_buf)); + return cfgp_lex_error (yyextra, + yylloc->last_line, yylloc->last_column, buf); + } + strncpy (yylval->string_buf, yytext, sizeof (yylval->string_buf)); + return IDENTIFIER; + + } + +{SECTION_OPEN} { LOC_COL_DEF_ADV; return OPENSECTION; } +{SECTION_CLOSE} { LOC_COL_DEF_ADV; return CLOSESECTION; } +{SEMICOLUMN} { LOC_COL_DEF_ADV; return SEMICOLUMN; } +"=" { LOC_COL_DEF_ADV; return EQUAL_TOKEN; } +"," { LOC_COL_DEF_ADV; return KOMMA; } +")" { LOC_COL_DEF_ADV; return LCLOSE; } +"(" { LOC_COL_DEF_ADV; return LOPEN; } + +[ \t]+ { + /* ignore whitespace */ + LOC_COL_DEF_ADV; + } + +\n { + /* ignore EOL */ + LOC_LINE_ADV(1); + } + + + /* we could try to return chars not matching any token to the parser and + * have parser generate a useful error; tried that, parser gives output: + * syntax error, unexpected $undefined, expecting OPENSECTION or EQUAL_TOKEN + * while the lexer error gives: + * lexer error (line 1, column 11): Unexpected character: ':' + */ + + +. { + char buf[256]; + snprintf (buf, sizeof(buf), "Unexpected character: '%c'", *yytext); + return cfgp_lex_error (yyextra, yylloc->last_line, + yylloc->last_column, buf); + } + + /* . { return (int) *yytext; }*/ + +%% + +void cfgp_setfile (FILE * f, yyscan_t scanner) +{ + yyset_in (f, scanner); +} diff --git a/src/modelconfig/configparser.y b/src/modelconfig/configparser.y new file mode 100644 index 0000000000000000000000000000000000000000..1b73c0ff558bcf332b802c2c0b241163e2043bda --- /dev/null +++ b/src/modelconfig/configparser.y @@ -0,0 +1,184 @@ + +%pure-parser +%error-verbose +%locations + +%parse-param {yyscan_t * scanner} +%lex-param {yyscan_t * scanner} +%parse-param {ParserParams * param} + +// Note lower versions might also work +%require "2.3" + +%name-prefix="cfgp_" +%defines + +%{ + + +#include +#include "src/modelconfig/configglue.h" + +#if defined __GNUC__ +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wunused-function" +#elif defined __SUNPRO_CC +#pragma disable_warn +#elif defined _MSC_VER +#pragma warning(push, 1) +#endif + + +%} + +%code requires { + + #ifndef YY_TYPEDEF_YY_SCANNER_T + #define YY_TYPEDEF_YY_SCANNER_T + typedef void* yyscan_t; + #endif + +} + + +%union { + struct + { + char string_buf [512]; + unsigned int curstringpos; + }; + +} + +%{ +#include "src/modelconfig/configlex.h" + +int cfgp_error (YYLTYPE * loc, yyscan_t * scanner, ParserParams * p, + const char * msg) +{ + if (loc) + { + return cfgp_parser_error (p, msg, loc->first_line, + loc->first_column, loc->last_line, loc->last_column); + } + else + { + return cfgp_parser_error (p, msg, 0,0,0,0); + } +} + +%} + +%start configfile +%token LITERAL_STRING +%token OPENSECTION +%token CLOSESECTION +%token IDENTIFIER +%token EQUAL_TOKEN +%token SEMICOLUMN +%token KOMMA +%token LOPEN +%token LCLOSE + + +%initial-action { + param->stacktop = 0; + param->sectionstack[0] = 0; + param->parser_error_code = 0; + param->parser_error_string = 0; +} + + + +%% + +initdummy: /* empty */ { + /* used to initialize vars */ + param->stacktop = 0; + } + +configfile: initdummy sectioncontents ; + +sectioncontents: sectioncontents entry | ; + +entry: key | subsection; + + +key: singlekey | multikey ; + +singlekey: IDENTIFIER EQUAL_TOKEN LITERAL_STRING SEMICOLUMN { + const char * key = & $1 [0]; + const char * value = & $3 [0]; + cf_createKey (param->configfile, + param->sectionstack[param->stacktop], key, &value, 1); + } + +multikeynonzero: KOMMA LITERAL_STRING { + param->keyvals[param->count++] = strdup ($2); + assert (param->count < param->maxsize); + } + +multikeyentry : multikeynonzero multikeyentry | ; + +multikeyinit : /* empty */ { + param->maxsize = 1000; + param->count = 0; + param->keyvals = (char**) malloc (sizeof(char*)*param->maxsize); + } + +multikeystart : LITERAL_STRING { + param->keyvals[param->count++] = strdup ($1); + assert (param->count < param->maxsize); + } + +/* this can probably be simplified */ +multikeybody: multikeystart multikeyentry | ; + +multikey: IDENTIFIER EQUAL_TOKEN LOPEN multikeyinit multikeybody LCLOSE + SEMICOLUMN { + unsigned int i; + /* when this is reduced we have all the keys */ + const char * key = & $1 [0]; + const char ** value = (const char **) param->keyvals; + cf_createKey (param->configfile, + param->sectionstack[param->stacktop], key, value, + param->count); + + /* can free strings */ + for (i=0; icount; ++i) + { + free (param->keyvals[i]); + } + free (param->keyvals); + param->keyvals = 0; + } + +opt_semicolumn: SEMICOLUMN | ; + +subsection_openaction: IDENTIFIER OPENSECTION + { + SectionHandle newsection; + assert(param->stacktop < sizeof(param->sectionstack)/sizeof(param->sectionstack[0])); + + cf_createSection (param->configfile, + param->sectionstack[param->stacktop], $1, + &newsection); + + /*cf_openSection (param->configfile, + param->sectionstack[param->stacktop], $1, &newsection); */ + param->sectionstack[++param->stacktop] = newsection; + }; + +subsection_closeaction: CLOSESECTION opt_semicolumn + { + assert (param->stacktop > 0); + SectionHandle old = param->sectionstack[param->stacktop--]; + cf_closeSection (param->configfile, old); + }; + +subsection: subsection_openaction sectioncontents subsection_closeaction ; + + +%% + + diff --git a/src/modelconfig/configstore.c b/src/modelconfig/configstore.c new file mode 100644 index 0000000000000000000000000000000000000000..abf926faf987912e27078479a3caa32a51ef609f --- /dev/null +++ b/src/modelconfig/configstore.c @@ -0,0 +1,369 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include "codes_base_config.h" +#include +#include +#ifdef HAVE_MALLOC_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include "configstore.h" + + +struct mcs_entry +{ + const char * name; + unsigned int is_section; + struct mcs_entry * next; + union + { + const char * value; + struct mcs_entry * child; + }; +}; + + +static inline mcs_entry * mcs_allocentry () +{ + mcs_entry * n = (mcs_entry *) malloc (sizeof (mcs_entry)); + memset (n, 0, sizeof (mcs_entry)); + return n; +} + +static inline void mcs_addtail (mcs_entry * e, mcs_entry * newe) +{ + assert (e); + while (e->next) + { + e = e->next; + } + e->next = newe; +} + +/* Add child to entry */ +static void mcs_addchild (mcs_entry * section, mcs_entry * child) +{ + mcs_entry * p; + + p = section->child; + if (!p) + { + section->child = child; + } + else + { + mcs_addtail (p, child); + } +} + + +/* Create empty subsection */ +static mcs_entry * mcs_createsection (const char * name) +{ + mcs_entry * n = mcs_allocentry (); + n->is_section = 1; + n->name = (name ? strdup (name) : 0); + return n; +} + +/* Create text entry */ +static mcs_entry * mcs_createvalue (const char * name, const char ** values, + unsigned int count) +{ + mcs_entry * n = mcs_allocentry (); + unsigned int i; + + n->is_section = 0; + n->next = 0; + n->name = (name ? strdup (name) : 0); + + for (i=0; iis_section = 0; + v->next = 0; + v->name = 0; + v->value = (values[i] ? strdup (values[i]) : 0); + mcs_addchild (n, v); + } + + return n; +} + +/* Recursively free entry and all following entries and children */ +static void mcs_freechain (mcs_entry * t) +{ + if (!t) + return; + + while (t) + { + mcs_entry * old = t; + + free ((void*) t->name); + if (t->is_section) + { + /* assert (!t->value); */ /* t->value and t->child are one... + (union)*/ + mcs_freechain (t->child); + } + else + { + /* free all child values */ + mcs_entry * v = t->child; + while (v) + { + mcs_entry * valentry = v; + assert (!v->name); + free ((void *) v->value); + v = v->next; + free (valentry); + } + } + t = t->next; + free (old); + } +} + +/* Remove (and free) named entry from section */ +int mcs_removechild (mcs_entry * section, const char * child) +{ + mcs_entry * e; + mcs_entry * prev; + + prev = 0; + e = section->child; + + assert (e->is_section); + if (!e->child) + return 0; + + + while (e) + { + if (!strcmp (child, e->name)) + { + /* found entry */ + if (!prev) + { + /* entry is first child */ + section->child = e->next; + } + else + { + prev->next = e->next; + } + + /* isolate e so we don't free the whole chain */ + e->next = 0; + mcs_freechain (e); + return 1; + } + e = e->next; + } + return 0; +} + +/* Free (recursively) section */ +int mcs_freeroot (mcs_entry * section) +{ + mcs_freechain (section); + return 1; +} + +static unsigned int mcs_chaincount (const mcs_entry * e) +{ + unsigned int ret = 0; + + while (e) + { + ++ret; + e = e->next; + } + + return ret; +} + +/* ============= high level functions ======================== */ + +/* Return empty tree */ +mcs_entry * mcs_initroot () +{ + return mcs_createsection (0); +} +/* Add child section to section; returns child section */ +mcs_entry * mcs_addsection (mcs_entry * e, const char * name) +{ + mcs_entry * newsec = mcs_createsection (name); + mcs_addchild (e, newsec); + return newsec; +} + +/* Add (multi-)key to section */ +mcs_entry * mcs_addkey (mcs_entry * e, const char * name, const char ** + values, unsigned int count) +{ + mcs_entry * newkey = mcs_createvalue (name, values, count); + mcs_addchild (e, newkey); + return newkey; +} + + +/* Returns true if entry is a subsection */ +int mcs_issection (const mcs_entry * e) +{ + return e->is_section; +} + +/* Returns number of children in section */ +int mcs_childcount (const mcs_entry * e) +{ + assert (e->is_section); + return mcs_chaincount (e->child); +} + +/* Return the number of values in the key */ +int mcs_valuecount (const mcs_entry * e) +{ + assert (!e->is_section); + return mcs_chaincount (e->child); +} + +/* + * If buf & bufsize == 0, returns the length of the key value (without + * terminating 0) or < 0 if error. + * Returns len of key value without ending '\0' + */ +int mcs_getvaluesingle (const mcs_entry * e, char * buf, unsigned int bufsize) +{ + if (e->is_section) + return MCS_WRONGTYPE; + + if (buf) + *buf = 0; + + if (!e->child) + return -1; + + if (!e->child->value) + return 0; + + if (bufsize) + { + strncpy (buf, e->child->value, bufsize-1); + buf[bufsize-1] = 0; + } + + + return strlen (e->child->value); +} + +/* Retrieve the values for this key */ +int mcs_getvaluemultiple (const mcs_entry * e, char ** buf, unsigned int * maxcount) +{ + unsigned int i = 0; + mcs_entry * t = e->child; + + assert (!e->is_section); + + while (t) + { + if (i == *maxcount) + return 0; + + assert (!t->name); + + buf[i] = (t->value ? strdup (t->value) : 0); + ++i; + t = t->next; + } + *maxcount = i; + return 1; +} + +/* Move to the next entry on this level */ +mcs_entry * mcs_next (const mcs_entry * e) +{ + return e->next; +} + +/* Move to the first child of this section */ +mcs_entry * mcs_child (const mcs_entry * e) +{ + assert (e->is_section); + return e->child; +} + +/* Look for a child node with the specified name */ +static mcs_entry * mcs_findchild (const mcs_entry * e, const char * name) +{ + mcs_entry * curchild = e->child; + + while (curchild) + { + if (!strcmp (curchild->name, name)) + break; + curchild = curchild->next; + } + return curchild; +} + + +mcs_entry * mcs_findsubsection (const mcs_entry * e, const char * name) +{ + mcs_entry * ret = mcs_findchild (e, name); + if (!ret) + return 0; + if (!ret->is_section) + return 0; + return ret; +} + +mcs_entry * mcs_findkey (const mcs_entry * e, const char * name) +{ + mcs_entry * ret = mcs_findchild (e, name); + if (!ret) + return 0; + if (ret->is_section) + return 0; + return ret; +} + +int mcs_listsection (const mcs_entry * e, mcs_section_entry * out, unsigned int maxcount) +{ + const mcs_entry * cur; + unsigned int i = 0; + + if (!e) + return 0; + if (!e->is_section) + return -1; + + cur = e->child; + + i=0; + while (cur && i < maxcount) + { + out[i].name = (cur->name ? strdup (cur->name) : 0); + out[i].is_section = cur->is_section; + out[i].childcount = mcs_chaincount (cur->child); + ++i; + cur = cur->next; + } + return i; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/modelconfig/configstore.h b/src/modelconfig/configstore.h new file mode 100644 index 0000000000000000000000000000000000000000..12aab9361d8b872fe9d7c0a5f9580fe7b85e771b --- /dev/null +++ b/src/modelconfig/configstore.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#ifndef SRC_COMMON_MODELCONFIG_CONFIGSTORE_H +#define SRC_COMMON_MODELCONFIG_CONFIGSTORE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Memory based storage for config file. + * + * + */ + +/* error codes */ +#define MCS_NOENT -1 /* no such entry */ +#define MCS_BUFSIZE -2 /* buffer size too small */ +#define MCS_WRONGTYPE -3 /* entry has wrong type */ + +struct mcs_entry; + +typedef struct mcs_entry mcs_entry; + + +/* Return empty tree */ +mcs_entry * mcs_initroot (); + +/* Add child section to section; returns child section */ +mcs_entry * mcs_addsection (mcs_entry * e, const char * name); + +/* Add (multi-)key to section */ +mcs_entry * mcs_addkey (mcs_entry * e, const char * name, const char ** + values, unsigned int count); + +/* Free subtree */ +int mcs_freeroot (mcs_entry * e); + +/* === examining tree === */ + +/* Returns true if entry is a subsection */ +int mcs_issection (const mcs_entry * e); + +/* Returns number of children in section */ +int mcs_childcount (const mcs_entry * e); + +/* Return the number of values in the key */ +int mcs_valuecount (const mcs_entry * e); + +/* Retrieve the values for this key; + * maxcount (input) contains the size of the buf array; + * maxcount (output) the number of entries returned */ +int mcs_getvaluemultiple (const mcs_entry * e, char ** buf, unsigned int * maxcount); + +/* Retrieve single value for this key; Returns number of characters in key + * value. */ +int mcs_getvaluesingle (const mcs_entry * e, char * buf, unsigned int + bufsize); + +/* Lookup the named subsection in section */ +mcs_entry * mcs_findsubsection (const mcs_entry * e, const char * name); + +/* Lookup the named key in section */ +mcs_entry * mcs_findkey (const mcs_entry * e, const char * name); + +/* Move to the next entry on this level */ +mcs_entry * mcs_next (const mcs_entry * e); + +/* Move to the first child of this section */ +mcs_entry * mcs_child (const mcs_entry * e); + + +typedef struct +{ + char * name; + int is_section; + unsigned int childcount; +} mcs_section_entry; + +/* returns number of entries written, or -1 on error */ +int mcs_listsection (const mcs_entry * a, mcs_section_entry * e, unsigned int + entries); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/modelconfig/configstoreadapter.c b/src/modelconfig/configstoreadapter.c new file mode 100644 index 0000000000000000000000000000000000000000..d5d89211b94a58daee39b09c9f39d3ae85c31d0b --- /dev/null +++ b/src/modelconfig/configstoreadapter.c @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include "codes_base_config.h" +#include +#ifdef HAVE_MALLOC_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif + +#include +#include "configstoreadapter.h" +#include "configstore.h" + +/* unused attribute is only used here, so use directly in source */ +#ifdef UNUSED +#elif defined(__GNUC__) +# define UNUSED(x) UNUSED_ ## x __attribute__((unused)) +#elif defined(__LCLINT__) +# define UNUSED(x) /*@unused@*/ x +#else +# define UNUSED(x) x +#endif /* UNUSED */ + +static int cfsa_getKey (void * handle, SectionHandle section, const char * name, + char * buf, size_t bufsize) +{ + mcs_entry * key = mcs_findkey ((mcs_entry*) (section ? section : handle), name); + int count; + char * tmp; + unsigned int dcount; + int ret = 1; + + if (!key) + return -1; + + + count = mcs_valuecount (key); + + if (count < 0) + return count; + + /* error because key is multival */ + if (count > 1) + return -2; + + /* if bufsize == 0 the user only wants to know the size and so we + * ignore buf */ + if (bufsize == 0) + { + return mcs_getvaluesingle (key, 0, 0); + } + + + dcount = 1; + mcs_getvaluemultiple (key, &tmp, &dcount); + + if (!dcount) + { + assert(buf); + *buf = 0; + ret = 0; + /* tmp was not modified no need to free */ + } + else + { + ret = strlen (tmp); + strncpy (buf, tmp, bufsize); + if (bufsize > 0) + buf[bufsize-1]=0; + free (tmp); + } + return ret; +} + +static int cfsa_getMultiKey (void * handle, SectionHandle section, const char *name, + char *** buf, size_t * e) +{ + mcs_entry * key = mcs_findkey ((mcs_entry*) (section ? section : handle), + name); + int count; + unsigned int dcount; + + *e = 0; + if (!key) + return -1; + + count = mcs_valuecount (key); + + if (count < 0) + return -2; + + *buf = (char **) malloc (sizeof (char **) * count); + dcount = count; + mcs_getvaluemultiple (key, *buf, &dcount); + *e = dcount; + + return 1; +} + +static int cfsa_listSection (void * handle, SectionHandle section, + SectionEntry * entries, size_t * maxentries) +{ + mcs_section_entry * out; + int count; + int ret = 0; + int i; + + if (!section) + section = handle; + + + count = mcs_childcount ((mcs_entry *)section); + if (count < 0) + { + *maxentries = 0; + return count; + } + + + if (count == 0) + { + *maxentries = 0; + return count; + } + + ret = count; + + out = (mcs_section_entry*) malloc (sizeof(mcs_section_entry)* *maxentries); + + count = mcs_listsection ((mcs_entry*)section, (mcs_section_entry*)out, *maxentries); + if (count < 0) + { + *maxentries = 0; + ret = count; + } + else + { + for (i=0; i= 0) + { + *count = c; + return 1; + } + else + { + return c; + } +} + + + +static struct ConfigVTable cfsa_template = { + .getKey = cfsa_getKey, + .getMultiKey = cfsa_getMultiKey, + .listSection = cfsa_listSection, + .openSection = cfsa_openSection, + .getSectionSize = cfsa_getSectionSize, + .closeSection = cfsa_closeSection, + .createSection = cfsa_createSection, + .createKey = cfsa_createKey, + .free = cfsa_free, + .data = 0 +}; + +struct ConfigVTable * cfsa_create (mcs_entry * e) +{ + struct ConfigVTable * newh = (struct ConfigVTable *) malloc (sizeof (struct ConfigVTable)); + *newh = cfsa_template; + newh->data = e; + return newh; +} + +struct ConfigVTable * cfsa_create_empty () +{ + return cfsa_create (mcs_initroot ()); +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/modelconfig/configstoreadapter.h b/src/modelconfig/configstoreadapter.h new file mode 100644 index 0000000000000000000000000000000000000000..36bb701a1fb7a304efa3c8e1e995d64ca1f5bb42 --- /dev/null +++ b/src/modelconfig/configstoreadapter.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#ifndef SRC_COMMON_MODELCONFIG_CONFIGSTOREADAPTER_H +#define SRC_COMMON_MODELCONFIG_CONFIGSTOREADAPTER_H + +#include "configfile.h" +#include "configstore.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Create a new configfile interface backed by a configstore */ +struct ConfigVTable * cfsa_create (mcs_entry * e); + +struct ConfigVTable * cfsa_create_empty (); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/modelconfig/configuration.c b/src/modelconfig/configuration.c new file mode 100644 index 0000000000000000000000000000000000000000..db689fd55be345d4c995653e63021b6f06f9ae51 --- /dev/null +++ b/src/modelconfig/configuration.c @@ -0,0 +1,609 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include +#include +#include +#include +#include +#include +#include "codes/configuration.h" +#include + +#include "configfile.h" +#include "txt_configfile.h" + +/* + * Global to hold configuration in memory + */ +ConfigHandle config; + +/* Global to hold LP configuration */ +config_lpgroups_t lpconf; + +int configuration_load (const char *filepath, + MPI_Comm comm, + ConfigHandle *handle) +{ + MPI_File fh; + MPI_Status status; + MPI_Offset txtsize; + FILE *f = NULL; + char *txtdata = NULL; + char *error = NULL; + int rc = 0; + char *tmp_path = NULL; + + rc = MPI_File_open(comm, (char*)filepath, MPI_MODE_RDONLY, MPI_INFO_NULL, &fh); + if (rc != MPI_SUCCESS) goto finalize; + + rc = MPI_File_get_size(fh, &txtsize); + if (rc != MPI_SUCCESS) goto finalize; + + txtdata = (char*) malloc(txtsize); + assert(txtdata); + + rc = MPI_File_read_all(fh, txtdata, txtsize, MPI_BYTE, &status); + if (rc != MPI_SUCCESS) goto finalize; + +#ifdef __APPLE__ + f = fopen(filepath, "r"); +#else + f = fmemopen(txtdata, txtsize, "rb"); +#endif + if (!f) { rc = 1; goto finalize; } + + *handle = txtfile_openStream(f, &error); + if (error) { rc = 1; goto finalize; } + + /* NOTE: posix version overwrites argument :(. */ + tmp_path = strdup(filepath); + assert(tmp_path); + (*handle)->config_dir = strdup(dirname(tmp_path)); + assert((*handle)->config_dir); + + rc = configuration_get_lpgroups(handle, "LPGROUPS", &lpconf); + +finalize: + if (fh != MPI_FILE_NULL) MPI_File_close(&fh); + if (f) fclose(f); + free(txtdata); + free(tmp_path); + if (error) { + fprintf(stderr, "config error: %s\n", error); + free(error); + } + + return rc; +} + +int configuration_get_value(ConfigHandle *handle, + const char *section_name, + const char *key_name, + const char *annotation, + char *value, + size_t len) +{ + SectionHandle section_handle; + int rc; + // reading directly from the config, so need to inject the annotation + // directly into the search string + char key_name_tmp[CONFIGURATION_MAX_NAME]; + char *key_name_full; + if (annotation==NULL){ + // sorry const type... we promise we won't change you + key_name_full = (char*) key_name; + } + else{ + if (snprintf(key_name_tmp, CONFIGURATION_MAX_NAME, "%s@%s", + key_name, annotation) >= CONFIGURATION_MAX_NAME) { + fprintf(stderr, + "config error: name@annotation pair too long: %s@%s\n", + key_name, annotation); + return 1; + } + else + key_name_full = key_name_tmp; + } + + rc = cf_openSection(*handle, ROOT_SECTION, section_name, §ion_handle); + if (rc != 1) return 0; + + rc = cf_getKey(*handle, section_handle, key_name_full, value, len); + (void) cf_closeSection(*handle, section_handle); + + return rc; +} + +int configuration_get_value_relpath( + ConfigHandle *handle, + const char * section_name, + const char * key_name, + const char *annotation, + char *value, + size_t length){ + char *tmp = (char*) malloc(length); + + int w = configuration_get_value(handle, section_name, key_name, annotation, tmp, + length); + if (w <= 0) + return w; + + /* concat the configuration value with the directory */ + w = snprintf(value, length, "%s/%s", (*handle)->config_dir, tmp); + + free(tmp); + return w; +} + +int configuration_get_multivalue(ConfigHandle *handle, + const char *section_name, + const char *key_name, + const char *annotation, + char ***values, + size_t *len) +{ + SectionHandle section_handle; + int rc; + // reading directly from the config, so need to inject the annotation + // directly into the search string + char key_name_tmp[CONFIGURATION_MAX_NAME]; + char *key_name_full; + if (annotation==NULL){ + // sorry const type... we promise we won't change you + key_name_full = (char*) key_name; + } + else{ + if (snprintf(key_name_tmp, CONFIGURATION_MAX_NAME, "%s@%s", + key_name, annotation) >= CONFIGURATION_MAX_NAME) { + fprintf(stderr, + "config error: name@annotation pair too long: %s@%s\n", + key_name, annotation); + return 1; + } + else + key_name_full = key_name_tmp; + } + + rc = cf_openSection(*handle, ROOT_SECTION, section_name, §ion_handle); + if (rc != 1) return rc; + + rc = cf_getMultiKey(*handle, section_handle, key_name_full, values, len); + (void) cf_closeSection(*handle, section_handle); + + return rc; +} + +int configuration_get_value_int (ConfigHandle *handle, + const char *section_name, + const char *key_name, + const char *annotation, + int *value) +{ + char valuestr[256]; + int rc = 1; + int r; + + r = configuration_get_value(handle, + section_name, + key_name, + annotation, + valuestr, + sizeof(valuestr)); + if (r > 0) + { + *value = atoi(valuestr); + rc = 0; + } + + return rc; +} + +int configuration_get_value_uint (ConfigHandle *handle, + const char *section_name, + const char *key_name, + const char *annotation, + unsigned int *value) +{ + char valuestr[256]; + int rc = 1; + int r; + + r = configuration_get_value(handle, + section_name, + key_name, + annotation, + valuestr, + sizeof(valuestr)); + if (r > 0) + { + *value = (unsigned int) atoi(valuestr); + rc = 0; + } + + return rc; +} + +int configuration_get_value_longint (ConfigHandle *handle, + const char *section_name, + const char *key_name, + const char *annotation, + long int *value) +{ + char valuestr[256]; + int rc = 1; + int r; + + r = configuration_get_value(handle, + section_name, + key_name, + annotation, + valuestr, + sizeof(valuestr)); + if (r > 0) + { + errno = 0; + *value = strtol(valuestr, NULL, 10); + rc = errno; + } + + return rc; +} + +int configuration_get_value_double (ConfigHandle *handle, + const char *section_name, + const char *key_name, + const char *annotation, + double *value) +{ + char valuestr[256]; + int rc = 1; + int r; + + r = configuration_get_value(handle, + section_name, + key_name, + annotation, + valuestr, + sizeof(valuestr)); + if (r > 0) + { + errno = 0; + *value = strtod(valuestr, NULL); + rc = errno; + } + + return rc; +} + +static void check_add_anno( + int anno_offset, + config_anno_map_t *map){ + if (anno_offset == -1) { + map->has_unanno_lp = 1; + if (!map->num_annos) + map->is_unanno_first = 1; + } + else{ + int a = 0; + for (; a < map->num_annos; a++){ + if (map->annotations[a].offset == anno_offset) { + map->num_anno_lps[a]++; + break; + } + } + if (a == map->num_annos){ + // we have a new anno! + assert(a < CONFIGURATION_MAX_ANNOS); + map->annotations[a].offset = anno_offset; + map->num_annos++; + map->num_anno_lps[a] = 1; + } // else anno was already there, do nothing + } +} +static void check_add_lp_type_anno( + int lp_name_offset, + int anno_offset, + config_lpgroups_t *lpgroups){ + uint64_t lpt_anno = 0; + for (; lpt_anno < lpgroups->lpannos_count; lpt_anno++){ + config_anno_map_t *map = &lpgroups->lpannos[lpt_anno]; + if (map->lp_name.offset == lp_name_offset){ + check_add_anno(anno_offset, map); + break; + } + } + if (lpt_anno == lpgroups->lpannos_count){ + // we haven't seen this lp type before + assert(lpt_anno < CONFIGURATION_MAX_TYPES); + config_anno_map_t *map = &lpgroups->lpannos[lpt_anno]; + // initialize this annotation map + map->lp_name.offset = lp_name_offset; + map->num_annos = 0; + map->has_unanno_lp = 0; + map->is_unanno_first = 0; + memset(map->num_anno_lps, 0, + CONFIGURATION_MAX_ANNOS*sizeof(*map->num_anno_lps)); + check_add_anno(anno_offset, map); + lpgroups->lpannos_count++; + } +} + +#define REALLOC_IF(_cap_var, _len_exp, _buf_var) \ + do { \ + while ((_cap_var) <= (_len_exp)) { \ + _cap_var *= 2; \ + _buf_var = realloc(_buf_var, (_cap_var) * sizeof(*_buf_var)); \ + assert(_buf_var); \ + } \ + } while (0) + +/* helper for setting up the canonical name mapping */ +static int check_add_uniq_str( + int ** offset_array, + char ** str_buf, + int * num_strs, + int * offset_array_cap, // buffer capacity for resizing + int * str_buf_len, + int * str_buf_cap, // buffer capacity for resizing + char const * str) +{ + int slen = strlen(str); + + for (int i = 0; i < *num_strs; i++) { + char const * b = (*str_buf) + (*offset_array)[i]; + int blen = strlen(b); + if (slen == blen && memcmp(b, str, blen) == 0) + return i; + } + + REALLOC_IF(*offset_array_cap, *num_strs, *offset_array); + REALLOC_IF(*str_buf_cap, *str_buf_len + slen + 1, *str_buf); + + // include null char + memcpy(*str_buf + *str_buf_len, str, slen+1); + (*offset_array)[*num_strs] = *str_buf_len; + *num_strs += 1; + *str_buf_len += slen+1; + return *num_strs-1; +} + +int configuration_get_lpgroups (ConfigHandle *handle, + const char *section_name, + config_lpgroups_t *lpgroups) +{ + SectionHandle sh; + SectionHandle subsh; + SectionEntry se[10]; + SectionEntry subse[10]; + size_t se_count = 10; + size_t subse_count = 10; + int i, j, lpt; + char data[256]; + // buffer mgmt vars + int num_uniq_group_names = 0; + int group_names_buf_len = 0; + int lp_names_buf_len = 0; + int anno_names_buf_len = 0; + int group_names_cap = 1; + int lp_names_cap = 1; + int anno_names_cap = 1; + int group_names_buf_cap = 1; + int lp_names_buf_cap = 1; + int anno_names_buf_cap = 1; + int name_pos; + + memset (lpgroups, 0, sizeof(*lpgroups)); + + int *group_names_offsets = + malloc(sizeof(*group_names_offsets) * group_names_cap); + int *lp_names_offsets = + malloc(sizeof(*lp_names_offsets) * lp_names_cap); + int *anno_names_offsets = + malloc(sizeof(*anno_names_offsets) * anno_names_cap); + lpgroups->group_names_buf = + malloc(sizeof(*lpgroups->group_names_buf) * group_names_buf_cap); + lpgroups->lp_names_buf = + malloc(sizeof(*lpgroups->lp_names_buf) * lp_names_buf_cap); + lpgroups->anno_names_buf = + malloc(sizeof(*lpgroups->anno_names_buf) * anno_names_buf_cap); + assert(group_names_offsets != NULL); + assert(lp_names_offsets != NULL); + assert(anno_names_offsets != NULL); + assert(lpgroups->group_names_buf != NULL); + assert(lpgroups->lp_names_buf != NULL); + assert(lpgroups->anno_names_buf != NULL); + + int ret = cf_openSection(*handle, ROOT_SECTION, section_name, &sh); + if (ret == -1) + return -1; + cf_listSection(*handle, sh, se, &se_count); + +#define CHECKED_STRTOL(_val, _field, _data) \ + do{ \ + errno = 0; \ + long int _rd = strtol(_data, NULL, 10); \ + if (_rd <= 0 || errno) \ + tw_error(TW_LOC, "bad value (expected positive integer) for " \ + "\"%s\": %s\n", _field, _data); \ + else \ + _val = _rd; \ + }while(0); + + for (i = 0; i < se_count; i++) + { + //printf("section: %s type: %d\n", se[i].name, se[i].type); + if (se[i].type == SE_SECTION) + { + subse_count = 10; + cf_openSection(*handle, sh, se[i].name, &subsh); + cf_listSection(*handle, subsh, subse, &subse_count); + name_pos = check_add_uniq_str(&group_names_offsets, + &lpgroups->group_names_buf, &num_uniq_group_names, + &group_names_cap, &group_names_buf_len, + &group_names_buf_cap, se[i].name); + lpgroups->lpgroups[i].name.offset = group_names_offsets[name_pos]; + lpgroups->lpgroups[i].repetitions = 1; + lpgroups->lpgroups_count++; + if (num_uniq_group_names != lpgroups->lpgroups_count) + tw_error(TW_LOC, + "config error: non-unique group names detected\n"); + + for (j = 0, lpt = 0; j < subse_count; j++) + { + if (subse[j].type == SE_KEY) + { + cf_getKey(*handle, subsh, subse[j].name, data, sizeof(data)); + //printf("key: %s value: %s\n", subse[j].name, data); + if (strcmp("repetitions", subse[j].name) == 0) + { + CHECKED_STRTOL(lpgroups->lpgroups[i].repetitions, + "repetitions", data); + //printf("\n Repetitions: %ld ", lpgroups->lpgroups[i].repetitions); + } + else + { + // to avoid copy, find a possible annotation, change the + // string in the config structure itself, then change + // back for posterity + char *c = strchr(subse[j].name, '@'); + if (c != NULL) { + *c = '\0'; + name_pos = check_add_uniq_str( + &anno_names_offsets, + &lpgroups->anno_names_buf, + &lpgroups->num_uniq_annos, + &anno_names_cap, + &anno_names_buf_len, + &anno_names_buf_cap, + c+1); + lpgroups->lpgroups[i].lptypes[lpt].anno.offset = + anno_names_offsets[name_pos]; + } + else + lpgroups->lpgroups[i].lptypes[lpt].anno.offset = -1; + + name_pos = check_add_uniq_str( + &lp_names_offsets, + &lpgroups->lp_names_buf, + &lpgroups->num_uniq_lptypes, + &lp_names_cap, + &lp_names_buf_len, + &lp_names_buf_cap, + subse[j].name); + lpgroups->lpgroups[i].lptypes[lpt].name.offset = + lp_names_offsets[name_pos]; + + if (c != NULL) + *c = '@'; + + // add to anno map + check_add_lp_type_anno( + lpgroups->lpgroups[i].lptypes[lpt].name.offset, + lpgroups->lpgroups[i].lptypes[lpt].anno.offset, + lpgroups); + CHECKED_STRTOL(lpgroups->lpgroups[i].lptypes[lpt].count, + lpgroups->lpgroups[i].lptypes[lpt].name, data); + lpgroups->lpgroups[i].lptypes_count++; + lpt++; + } + } + } + cf_closeSection(*handle, subsh); + } + } + + // set up the string pointers + lpgroups->group_names = + malloc(lpgroups->lpgroups_count * sizeof(*lpgroups->group_names)); + lpgroups->lp_names = + malloc(lpgroups->num_uniq_lptypes * sizeof(*lpgroups->lp_names)); + assert(lpgroups->group_names); + assert(lpgroups->lp_names); + + for (int i = 0; i < lpgroups->lpgroups_count; i++) { + lpgroups->group_names[i] = lpgroups->group_names_buf + + group_names_offsets[i]; + } + for (int i = 0; i < lpgroups->num_uniq_lptypes; i++) { + lpgroups->lp_names[i] = lpgroups->lp_names_buf + + lp_names_offsets[i]; + } + if (lpgroups->num_uniq_annos == 0) { + free(lpgroups->anno_names_buf); + lpgroups->anno_names = NULL; + lpgroups->anno_names_buf = NULL; + } + else { + lpgroups->anno_names = + malloc(lpgroups->num_uniq_annos * sizeof(*lpgroups->anno_names)); + assert(lpgroups->anno_names); + for (int i = 0; i < lpgroups->num_uniq_annos; i++) { + lpgroups->anno_names[i] = lpgroups->anno_names_buf + + anno_names_offsets[i]; + } + } + + // everything is set up in offset mode, now make a second pass and convert + // to pointers + for (int g = 0; g < lpgroups->lpgroups_count; g++) { + config_lpgroup_t *lpg = &lpgroups->lpgroups[g]; + lpg->name.ptr = lpgroups->group_names_buf + lpg->name.offset; + for (int t = 0; t < lpg->lptypes_count; t++) { + config_lptype_t *lpt = &lpg->lptypes[t]; + lpt->name.ptr = lpgroups->lp_names_buf + lpt->name.offset; + lpt->anno.ptr = + (lpt->anno.offset == -1) + ? NULL + : lpgroups->anno_names_buf + lpt->anno.offset; + } + } + for (int m = 0; m < lpgroups->lpannos_count; m++) { + config_anno_map_t *map = &lpgroups->lpannos[m]; + map->lp_name.ptr = lpgroups->lp_names_buf + map->lp_name.offset; + for (int a = 0; a < map->num_annos; a++) { + map->annotations[a].ptr = + (map->annotations[a].offset == -1) + ? NULL + : lpgroups->anno_names_buf + map->annotations[a].offset; + } + } + + cf_closeSection(*handle, sh); + + free(group_names_offsets); + free(lp_names_offsets); + free(anno_names_offsets); + + return 0; +} + +/* + * Helper function - get the position in the LP annotation list of the + * given annotation. Used for configuration schemes where an array of + * configuration values is generated based on the annotations in + * config_anno_map_t + * If anno is not found or a NULL anno is passed in, + * -1 is returned */ +int configuration_get_annotation_index(const char * anno, + const config_anno_map_t * anno_map){ + if (anno == NULL) return -1; + for (uint64_t i = 0; i < anno_map->num_annos; i++){ + if (!strcmp(anno, anno_map->annotations[i].ptr)){ + return (int)i; + } + } + return -1; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/modelconfig/txt_configfile.c b/src/modelconfig/txt_configfile.c new file mode 100644 index 0000000000000000000000000000000000000000..d0840895cb8ccec8e6b3ba75e34fbaae0ee99cf1 --- /dev/null +++ b/src/modelconfig/txt_configfile.c @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include +#include +#include "txt_configfile.h" +#include "configglue.h" +#include "src/modelconfig/configparser.h" +#include "src/modelconfig/configlex.h" +#include "configstoreadapter.h" + +#define MAX_CONFIG_SIZE 10*1024*1024 + +/* BISON doesn't declare the prototype? */ +int cfgp_parse (yyscan_t * scanner, ParserParams * param); + +static void show_indent (FILE * f, unsigned int ind) +{ + unsigned int i; + + for (i=0; itype) + { + case SE_SECTION: + { + SectionHandle newsec; + + fprintf (f, "%s { \n", entry->name); + + ret = mymin(ret, cf_openSection (h, s, entry->name, &newsec)); + if (ret >= 0) + { + ret = mymin (dump_section (f, h, newsec, indent + 2), ret); + show_indent (f, indent); + fprintf (f, "}\n"); + ret = mymin (ret, cf_closeSection (h, newsec)); + } + break; + } + case SE_KEY: + { + char buf[255]; + ret = mymin (ret, cf_getKey (h, s, entry->name, &buf[0], sizeof(buf))); + if (ret >= 0) + { + fprintf (f, "%s = \"%s\";\n", entry->name, buf); + } + break; + } + case SE_MULTIKEY: + { + char ** ptrs; + size_t size; + size_t j; + ret = mymin (ret, cf_getMultiKey (h, s, entry->name, &ptrs, &size)); + if (ret >= 0) + { + fprintf (f,"%s = (", entry->name); + for (j=0; j= 0) + { + ret = mymin (ret, dump_entry (f, h, s, indent, &entries[i])); + } + free ((void*)entries[i].name); + } + +fail: + free (entries); + return ret; +} + + +int txtfile_writeConfig (struct ConfigVTable * cf, SectionHandle h, FILE * f, char ** err) +{ + int ret; + assert(err); + assert(f); + + *err = 0; + + if ((ret = dump_section (f, cf, h, 0)) < 0) + { + *err = strdup ("Error accessing config tree!"); + return ret; + } + + return ret; +} + +struct ConfigVTable * txtfile_openStream (FILE * f, char ** err) +{ + long size; + ParserParams p; + yyscan_t scanner; + int reject; + char buf[512]; + + assert(err); + + *err=0; + + /* get file size */ + fseek (f, 0, SEEK_END); + + size = ftell (f); + + fseek (f, 0, SEEK_SET); + if (size > MAX_CONFIG_SIZE) + { + *err = strdup ("Config file too large! Not parsing!"); + return 0; + } + + cfgp_lex_init_extra (&p, &scanner); + cfgp_set_in (f, scanner); + cfgp_initparams (&p, cfsa_create (mcs_initroot ())); + reject = cfgp_parse((yyscan_t*)scanner, &p); + cfgp_lex_destroy (scanner); + + /* either we have a valid confighandle or we have a parser error... */ + /* not true: we can have a partial config tree */ + // assert((p.error_code || p.configfile) && (!p.error_code || !p.configfile)); + + /* If ther parser failed we need to have an error code */ + assert(!reject || p.parser_error_code || p.lexer_error_code); + assert(!p.lexer_error_string || p.lexer_error_code); + assert(!p.parser_error_string || p.parser_error_code); + + if (!cfgp_parse_ok (&p, buf, sizeof(buf))) + { + *err = strdup (buf); + } + else + { + assert(!p.parser_error_string); + assert(!p.lexer_error_string); + if (err) *err = 0; + } + + cfgp_freeparams (&p); + + return p.configfile; + } + +struct ConfigVTable * txtfile_openConfig (const char * filename, char ** error) +{ + FILE * f; + struct ConfigVTable * ret; + + + f = fopen (filename, "r"); + if (!f) + { + char buf[255]; + strerror_r (errno, buf, sizeof(buf)); + *error = strdup (buf); + return 0; + } + + ret = txtfile_openStream (f, error); + + fclose (f); + + return ret; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/modelconfig/txt_configfile.h b/src/modelconfig/txt_configfile.h new file mode 100644 index 0000000000000000000000000000000000000000..7610661224547a2cffb36bc338f6399f34fa9ab1 --- /dev/null +++ b/src/modelconfig/txt_configfile.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#ifndef SRC_COMMON_MODELCONFIG_TXTFILE_CONFIGFILE_H +#define SRC_COMMON_MODELCONFIG_TXTFILE_CONFIGFILE_H + + +#include +#include "configfile.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * ConfigFile implementation that stores data in a text file + */ + + +/** + * returns ConfigVTable, if all is OK *err is set to 0, + * otherwise *err is set to a pointer to the error string + * (which needs to be freed by the user) + * NOTE that even if an error occurred, a partial ConfigVTable tree + * can be returned. + */ +struct ConfigVTable * txtfile_openConfig (const char * filename, char ** err); + +/** + * returns ConfigVTable, if all is OK *err is set to 0, + * otherwise *err is set to a pointer to the error string + * (which needs to be freed by the user) + * NOTE that even if an error occurred, a partial ConfigVTable tree + * can be returned. + */ +struct ConfigVTable * txtfile_openStream (FILE * f, char ** err); + + +/** + * Write ConfigVTable to disk (in a format supported by _open). + * Returns >=0 if all went OK, < 0 otherwise in which + * case *err is set to a pointer to an error string, which needs to be + * freed by the user. + */ +int txtfile_writeConfig (struct ConfigVTable * h, SectionHandle h2, FILE * out, char ** err); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/util/README.codes-mapping.txt b/src/util/README.codes-mapping.txt new file mode 100644 index 0000000000000000000000000000000000000000..adcc75dd2d6aadf6c6b006105b8cab7c6e9d4f7e --- /dev/null +++ b/src/util/README.codes-mapping.txt @@ -0,0 +1,142 @@ +Codes Mapping API Overview +========================== + +- The codes-mapping.h header file contains the function definitions for the codes LP mapping. + +Step 1: Specifying the LP types in the config file: + +- Here is an example of a config file that specifies the codes LP mapping +-------------------------------example-test.conf----------------------------- +LPGROUPS +{ + MODELNET_GRP + { + repetitions="16"; + server="1"; + example_net="1"; + } +} +------------------------------------------------------------------------------ +In this config file, there are multiple LP types defined in a single LP group (As we will see in a later +example, there can be multiple LP groups in a config file too). There is 1 server LP and 1 example_net +LP type in a group and this combination is repeated 16 time (repetitions="16"). ROSS will assign the +LPs to the PEs (PEs is an abstraction for MPI rank in ROSS) by placing 1 server LP then 1 example_net +LP a total of 16 times. This configuration is useful if there is some form of communication involved +between the server and example_net LP types, in which case ROSS will place them on the same PE and +communication between server and example_net LPs will not involve remote messages. +The number of server and example_net LPs can be more than 1. Lets assume if we have two example_net +LPs for each server then the config file will have the following format: + +-------------------------------example-test2.conf----------------------------- +LPGROUPS +{ + MODELNET_GRP + { + repetitions="16"; + server="1"; + example_net="2"; + } +} +------------------------------------------------------------------------------ + +Step 2: Loading the config file in the model: + +After the initialization function calls of ROSS (tw_init), the configuration file can be loaded in the +example program using: + +configuration_load(example-test.conf, MPI_COMM_WORLD, &config); + +Step 3: Each LP type must register itself with the lp_type_register before setting up the codes-mapping. +Following is an example function that registers 'server' lp type. + +static void svr_add_lp_type() +{ + lp_type_register("server", svr_get_lp_type()); +} + +Step 4: Call to codes_mapping_setup that sets up the LPs of each registered LP type as specified in the config +file. + +codes_mapping_setup(); + +Step 5: Querying number of LPs in a group/repetition. + +int codes_mapping_get_lp_count(group_name, 1, lp_type_name, NULL, 0); + +The second argument indicates whether to include the number of repetitions into +the count or not (the NULL, 0 arguments will be discussed later). For example, +to query the number of server LPs in example-test2.conf file, calling + +num_servers = codes_mapping_get_lp_count("MODELNET_GRP", 1, "server", NULL, 0); + +will return 2. + +Step 6: Querying number of repetitions in a particular group, use + +int codes_mapping_get_group_reps(group_name); + +For example, to query the number of repetitions in example-test2.conf file, calling + +num_repetitions = codes_mapping_get_group_reps("MODELNET_GRP"); + +will return 16. + +=== LP to PE mapping for parallel simulations === + +In the case of parallel simulations using MPI, the LP mapping explained in Step +1 still holds. However, these LPs must also be mapped to PEs, which can be an +arbitrary mapping in ROSS. We simply assign the first N LPs to the first PE, the +second N to the second PE, and so forth, where N is the floor of the LP count +and the PE count. If the number of LPs is not divisible by the number of PEs, +then the first N+1 LPs are mapped to the first PE and so on, until the remainder +has been taken care of. + +=== Namespaces supported by codes mapping API === +The configuration scheme suppports "annotation"-based specifications. For +example: + +------------------------------------------------------------------------------- +LPGROUPS +{ + GROUP_1 + { + repetitions="16"; + server@foo="1"; + example_net@foo="1"; + } + + SWITCH + { + repetitions="1"; + example_net@foo="1"; + example_net@bar="1"; + } + + GROUP_2 + { + repetitions="16"; + server@bar="1"; + example_net@bar="1"; + } +} + +PARAMS +{ + net_bandwidth@foo="100"; + net_bandwidth@bar="50"; +} +------------------------------------------------------------------------------- + +In this example, the example_net LP will be configured corresponding to their +annotations "foo" and "bar". Not only does this allow specialization of +otherwise identical models, this also presents the opportunity to provide +namespace functionality to the mapping API. + +Current namespace support includes (see codes_mapping.h for more details) +- Global (e.g., LPs). Additional specializations for doing lookups corresponding + to a specific annotation, to support use cases such as the two example_net's + in the SWITCH group. +- LP-specific namespace (0..N) where N is the number of LPs of a specific type + (codes_mapping_get_lp_relative_id and codes_mapping_get_lpid_from_relative) + - relative IDs can be with respect to a particular group, a particular + annotation, both, or neither diff --git a/src/util/README.lp-io.txt b/src/util/README.lp-io.txt new file mode 100644 index 0000000000000000000000000000000000000000..ba950e6f2b58317288c5e82b218ff9ebee73218f --- /dev/null +++ b/src/util/README.lp-io.txt @@ -0,0 +1,53 @@ +LP-IO +----- + +LP-IO is a simple API for writing data collectively from a ROSS simulation. +It is best suited for relatively compact final statistics from each LP +rather than for ongoing event logging. + +API +--- + +lp_io_prepare(): call before tw_run as a collective operation. This +prepares a directory to hold the simulation results. If the +LP_IO_UNIQ_SUFFIX flag is specified, the lp-io will append a unique +identifier to the specified directory name based on the rank 0 pid and +the current unix time. + +lp_io_write(): call at any time during the simulation itself (i.e. in an +event handler or in the lp finalize() function). This is not a collective +call. The caller must specify a string identifier (which will become a file +within the output directory) as well as the buffer and size to write. + +NOTES on identifiers: +- Each LP can use as many identifiers as it wants to. +- Identifiers do not have to be coordinated across LPs. For example, some + LP types may use "lpdata1" and others may use "lpdata2", while others + don't write data at all. +- Each identifier can be written to as many times as needed. It just + appends additional data on each write call. + +lp_io_flush(): call after tw_run as a collective operation. This will +aggregate all data written by the simulation with lp_io_write() calls and +store data in the output directory using collective write operations. + +Example: +-------- +See lp-io-test. + +To run sequentially: "./lp-io-test --sync=1" + +To run in parallel: "mpiexec -n 8 ./lp-io-test --sync=2" + +This example will generate two output files. The output files are in text +format so that you can view them with "cat" or a text editor. + +Limitations: +--------- +- The code allocates a copy of all memory buffers. +- The aggregation could be optimized further. Right now it includes a O(N) + step to construct a global list of identifiers used by the model. +- There is a fixed (but arbitrary) limit on identifier string length and on + the total number of identifiers used by the simulation. This was done to + simplify the implementation rather than to address any particular resource + limitation. diff --git a/src/util/codes-jobmap-method-impl.h b/src/util/codes-jobmap-method-impl.h new file mode 100644 index 0000000000000000000000000000000000000000..1aa7de5a090e31ec1a469bec4390f69f008013d5 --- /dev/null +++ b/src/util/codes-jobmap-method-impl.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#ifndef CODES_JOBMAP_METHOD_IMPL +#define CODES_JOBMAP_METHOD_IMPL + +#include +#include "codes/codes-jobmap.h" + +struct codes_jobmap_impl { + /* returns nonzero on failure (to distinguish between no-state (dummy) and + * failure) */ + int (*configure)(void const * params, void ** ctx); + void (*destroy)(void * ctx); + struct codes_jobmap_id (*to_local) (int id, void const * ctx); + int (*to_global) (struct codes_jobmap_id id, void const * ctx); + int (*get_num_jobs)(void const * ctx); + int (*get_num_ranks)(int job_id, void const * ctx); +}; + +struct codes_jobmap_ctx { + enum codes_jobmap_type type; + struct codes_jobmap_impl *impl; + void * ctx; +}; + +#endif + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/util/codes-jobmap.c b/src/util/codes-jobmap.c new file mode 100644 index 0000000000000000000000000000000000000000..ed77b2beb4c911e1520ab40134896198ff2abba4 --- /dev/null +++ b/src/util/codes-jobmap.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2015 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include +#include + +#include "codes-jobmap-method-impl.h" +#include "codes/codes-jobmap.h" + +extern struct codes_jobmap_impl jobmap_dummy_impl; +extern struct codes_jobmap_impl jobmap_list_impl; +extern struct codes_jobmap_impl jobmap_identity_impl; + +struct codes_jobmap_ctx * +codes_jobmap_configure(enum codes_jobmap_type t, void const * params) +{ + struct codes_jobmap_ctx *c = malloc(sizeof(*c)); + assert(c); + int rc; + + c->type = t; + switch(t) { + case CODES_JOBMAP_IDENTITY: + c->impl = &jobmap_identity_impl; + break; + case CODES_JOBMAP_LIST: + c->impl = &jobmap_list_impl; + break; + case CODES_JOBMAP_DUMMY: + c->impl = &jobmap_dummy_impl; + break; + default: + free(c); + fprintf(stderr, "ERROR: unknown jobmap type %d\n", t); + return NULL; + } + rc = c->impl->configure(params, &c->ctx); + if (rc) { + fprintf(stderr, "ERROR: failed to configure jobmap type %d\n", t); + free(c); + return NULL; + } + else + return c; +} + +void codes_jobmap_destroy(struct codes_jobmap_ctx *c) +{ + c->impl->destroy(c->ctx); + free(c); +} + +struct codes_jobmap_id codes_jobmap_to_local_id( + int id, + struct codes_jobmap_ctx const * c) +{ + return c->impl->to_local(id, c->ctx); +} + +int codes_jobmap_to_global_id( + struct codes_jobmap_id id, + struct codes_jobmap_ctx const * c) +{ + return c->impl->to_global(id, c->ctx); +} + +int codes_jobmap_get_num_jobs(struct codes_jobmap_ctx const * c) +{ + return c->impl->get_num_jobs(c->ctx); +} + +int codes_jobmap_get_num_ranks(int job_id, struct codes_jobmap_ctx const * c) +{ + return c->impl->get_num_ranks(job_id, c->ctx); +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/util/codes-mapping-context.c b/src/util/codes-mapping-context.c new file mode 100644 index 0000000000000000000000000000000000000000..adba0279948dc16c7aabfa0b75f1b3f7d5f6e4da --- /dev/null +++ b/src/util/codes-mapping-context.c @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2015 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include +#include + +static struct codes_mctx const CODES_MCTX_DEFAULT_VAL = { + .type = CODES_MCTX_GROUP_MODULO, + .u = { + .group_modulo = { + .anno = { + .cid = -1, + } + } + } +}; + +struct codes_mctx const * const CODES_MCTX_DEFAULT = &CODES_MCTX_DEFAULT_VAL; + +struct codes_mctx codes_mctx_set_global_direct(tw_lpid lpid) +{ + struct codes_mctx rtn; + rtn.type = CODES_MCTX_GLOBAL_DIRECT; + rtn.u.global_direct.lpid = lpid; + return rtn; +} + +static struct codes_mctx set_group_modulo_common( + enum codes_mctx_type type, + char const * annotation, + bool ignore_annotations) +{ + struct codes_mctx rtn; + rtn.type = type; + if (ignore_annotations) + rtn.u.group_modulo.anno.cid = -1; + else + rtn.u.group_modulo.anno.cid = + codes_mapping_get_anno_cid_by_name(annotation); + return rtn; +} +struct codes_mctx codes_mctx_set_group_modulo( + char const * annotation, + bool ignore_annotations) +{ + return set_group_modulo_common(CODES_MCTX_GROUP_MODULO, annotation, + ignore_annotations); +} + +struct codes_mctx codes_mctx_set_group_modulo_reverse( + char const * annotation, + bool ignore_annotations) +{ + return set_group_modulo_common(CODES_MCTX_GROUP_MODULO_REVERSE, annotation, + ignore_annotations); +} + +struct codes_mctx codes_mctx_set_group_direct( + int offset, + char const * annotation, + bool ignore_annotations) +{ + struct codes_mctx rtn; + rtn.type = CODES_MCTX_GROUP_DIRECT; + rtn.u.group_direct.offset = offset; + if (ignore_annotations) + rtn.u.group_direct.anno.cid = -1; + else + rtn.u.group_direct.anno.cid = + codes_mapping_get_anno_cid_by_name(annotation); + return rtn; +} + +/* helper function to do a codes mapping - this function is subject to change + * based on what types of ctx exist */ +tw_lpid codes_mctx_to_lpid( + struct codes_mctx const * ctx, + char const * dest_lp_name, + tw_lpid sender_gid) +{ + struct codes_mctx_annotation const *anno; + // short circuit for direct mappings + switch (ctx->type) { + case CODES_MCTX_GLOBAL_DIRECT: + return ctx->u.global_direct.lpid; + case CODES_MCTX_GROUP_MODULO: + case CODES_MCTX_GROUP_MODULO_REVERSE: + anno = &ctx->u.group_modulo.anno; + break; + case CODES_MCTX_GROUP_DIRECT: + anno = &ctx->u.group_direct.anno; + break; + default: + assert(0); + } + + char sender_group[MAX_NAME_LENGTH]; + int unused, rep_id, offset; + + // get sender info + codes_mapping_get_lp_info(sender_gid, sender_group, &unused, NULL, &unused, + NULL, &rep_id, &offset); + + char const * anno_str; + if (anno->cid < 0) + anno_str = NULL; + else + anno_str = codes_mapping_get_anno_name_by_cid(anno->cid); + + int dest_offset; + if (ctx->type == CODES_MCTX_GROUP_MODULO || + ctx->type == CODES_MCTX_GROUP_MODULO_REVERSE) { + int num_dest_lps = codes_mapping_get_lp_count(sender_group, 1, + dest_lp_name, anno_str, anno->cid == -1); + if (num_dest_lps == 0) + tw_error(TW_LOC, + "ERROR: Found no LPs of type %s in group %s " + "(source lpid %lu) with annotation: %s\n", + dest_lp_name, sender_group, sender_gid, + anno->cid == -1 ? "ignored" : + codes_mapping_get_anno_name_by_cid(anno->cid)); + + dest_offset = offset % num_dest_lps; + if (ctx->type == CODES_MCTX_GROUP_MODULO_REVERSE) + dest_offset = num_dest_lps - 1 - dest_offset; + } + else if (ctx->type == CODES_MCTX_GROUP_DIRECT) { + dest_offset = ctx->u.group_direct.offset; + } + else + assert(0); + + tw_lpid rtn; + codes_mapping_get_lp_id(sender_group, dest_lp_name, anno_str, + anno->cid == -1, rep_id, dest_offset, &rtn); + return rtn; +} + +char const * codes_mctx_get_annotation( + struct codes_mctx const *ctx, + char const * dest_lp_name, + tw_lpid sender_id) +{ + switch(ctx->type) { + case CODES_MCTX_GLOBAL_DIRECT: + return codes_mapping_get_annotation_by_lpid(sender_id); + case CODES_MCTX_GROUP_MODULO: + case CODES_MCTX_GROUP_MODULO_REVERSE: + // if not ignoring the annotation, just return what's in the + // context + if (ctx->u.group_modulo.anno.cid >= 0) + return codes_mapping_get_anno_name_by_cid( + ctx->u.group_modulo.anno.cid); + break; + case CODES_MCTX_GROUP_DIRECT: + if (ctx->u.group_direct.anno.cid >= 0) + return codes_mapping_get_anno_name_by_cid( + ctx->u.group_direct.anno.cid); + break; + default: + tw_error(TW_LOC, "unrecognized or uninitialized context type: %d", + ctx->type); + return NULL; + } + // at this point, we must be a group-wise mapping ignoring annotations + + char group[MAX_NAME_LENGTH]; + int dummy; + // only need the group name + codes_mapping_get_lp_info(sender_id, group, &dummy, NULL, &dummy, NULL, + &dummy, &dummy); + + return codes_mapping_get_annotation_by_name(group, dest_lp_name); +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/util/codes_mapping.c b/src/util/codes_mapping.c new file mode 100644 index 0000000000000000000000000000000000000000..90e8f4a61a1bd28048d3dadf6303e97323f6455c --- /dev/null +++ b/src/util/codes_mapping.c @@ -0,0 +1,701 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +/* SUMMARY: + * CODES custom mapping file for ROSS + */ +#include "codes/codes_mapping.h" + +#define CODES_MAPPING_DEBUG 0 + +/* number of LPs assigned to the current PE (abstraction of MPI rank). + * for lp counts which are not divisible by the number of ranks, keep + * modulus around */ +static int lps_per_pe_floor = 0; +static int lps_leftover = 0; + +static int mem_factor = 256; + +static int mini(int a, int b){ return a < b ? a : b; } + +// compare passed in annotation strings (NULL or nonempty) against annotation +// strings in the config (empty or nonempty) +static int cmp_anno(const char * anno_user, const char * anno_config){ + return anno_user == NULL ? anno_config == NULL + : (anno_config != NULL + && !strcmp(anno_user, anno_config)); +} + + +#if 0 +// TODO: this code seems useful, but I'm not sure where to put it for the time +// being. It should be useful when we are directly reading from the +// configuration file, which has the unprocessed annotated strings + +// return code matches that of strcmp and friends, checks +// lp_type_name@annotation against full name +// NOTE: no argument should be NULL or invalid strings +static int strcmp_anno( + const char * full_name, + const char * prefix, + const char * annotation){ + int i; + // first phase - check full_name against prefix + for (i = 0; i < MAX_NAME_LENGTH; i++){ + char cf = full_name[i], cl = prefix[i]; + if (cl == '\0') + break; // match successful + else if (cf != cl) // captures case where cf is null char or @ + return (int)(cf-cl); // lp name on full doesn't match + } + if (i==MAX_NAME_LENGTH) return 1; + // second phase - ensure the next character after the match is an @ + if (full_name[i] != '@') return -1; + // third phase, compare the remaining full_name against annotation + return strcmp(full_name+i+1, annotation); +} +#endif + +/* char arrays for holding lp type name and group name*/ +// (unused var atm) static char local_group_name[MAX_NAME_LENGTH]; +static char local_lp_name[MAX_NAME_LENGTH], + local_annotation[MAX_NAME_LENGTH]; + +int codes_mapping_get_lps_for_pe() +{ + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); +#if CODES_MAPPING_DEBUG + printf("%d lps for rank %d\n", lps_per_pe_floor+(g_tw_mynode < lps_leftover), rank); +#endif + return lps_per_pe_floor + (g_tw_mynode < lps_leftover); +} + +/* Takes the global LP ID and returns the rank (PE id) on which the LP is mapped */ +tw_peid codes_mapping( tw_lpid gid) +{ + int lps_on_pes_with_leftover = lps_leftover * (lps_per_pe_floor+1); + if (gid < lps_on_pes_with_leftover){ + return gid / (lps_per_pe_floor+1); + } + else{ + return (gid-lps_on_pes_with_leftover)/lps_per_pe_floor + lps_leftover; + } + /*return gid / lps_per_pe_floor;*/ +} + +int codes_mapping_get_group_reps(const char* group_name) +{ + int grp; + for(grp = 0; grp < lpconf.lpgroups_count; grp++) + { + if(strcmp(lpconf.lpgroups[grp].name.ptr, group_name) == 0) + return lpconf.lpgroups[grp].repetitions; + } + return -1; +} + +int codes_mapping_get_lp_count( + const char * group_name, + int ignore_repetitions, + const char * lp_type_name, + const char * annotation, + int ignore_annos){ + int lp_type_ct_total = 0; + + // check - if group name is null, then disable ignore_repetitions (the + // former takes precedence) + if (group_name == NULL) + ignore_repetitions = 0; + for (int g = 0; g < lpconf.lpgroups_count; g++){ + const config_lpgroup_t *lpg = &lpconf.lpgroups[g]; + // iterate over the lps if the group is null (count across all groups) + // or if the group names match + if (group_name == NULL || strcmp(lpg->name.ptr, group_name) == 0){ + for (int l = 0; l < lpg->lptypes_count; l++){ + const config_lptype_t *lpt = &lpg->lptypes[l]; + if (strcmp(lp_type_name, lpt->name.ptr) == 0){ + // increment the count if we are ignoring annotations, + // query and entry are both unannotated, or if the + // annotations match + if (ignore_annos || cmp_anno(annotation, lpt->anno.ptr)){ + if (ignore_repetitions) + lp_type_ct_total += lpt->count; + else + lp_type_ct_total += lpt->count * lpg->repetitions; + if (ignore_annos == 1) + break; + } + } + } + if (group_name != NULL) break; // we've processed the exact group + } + } + // no error needed here - 0 is a valid value + return lp_type_ct_total; +} + +void codes_mapping_get_lp_id( + const char * group_name, + const char * lp_type_name, + const char * annotation, + int ignore_anno, + int rep_id, + int offset, + tw_lpid * gid){ + // sanity checks + if (rep_id < 0 || offset < 0 || group_name == NULL || lp_type_name == NULL) + goto ERROR; + *gid = 0; + // for each group + for (int g = 0; g < lpconf.lpgroups_count; g++){ + const config_lpgroup_t *lpg = &lpconf.lpgroups[g]; + // in any case, count up the lps (need for repetition handling) + tw_lpid rep_count = 0; + for (int l = 0; l < lpg->lptypes_count; l++){ + rep_count += lpg->lptypes[l].count; + } + // does group name match? + if (strcmp(lpg->name.ptr, group_name) == 0){ + tw_lpid local_lp_count = 0; + // for each lp type + for (int l = 0; l < lpg->lptypes_count; l++){ + const config_lptype_t *lpt = &lpg->lptypes[l]; + // does lp name match? + if (strcmp(lpt->name.ptr, lp_type_name) == 0){ + // does annotation match (or are we ignoring annotations?) + if (ignore_anno || cmp_anno(annotation, lpt->anno.ptr)){ + // return if sane offset + if (offset >= (int) lpt->count){ + goto ERROR; + } + else{ + *gid += (rep_count * (tw_lpid)rep_id) + + local_lp_count + (tw_lpid)offset; + return; + } + } + } + local_lp_count += lpt->count; + } + // after a group match, short circuit to end if lp not found + goto ERROR; + } + // group name doesn't match, add count to running total and move on + else{ + *gid += lpg->repetitions * rep_count; + } + } +ERROR: + // LP not found + tw_error(TW_LOC, "Unable to find LP id given " + "group \"%s\", " + "typename \"%s\", " + "annotation \"%s\", " + "repetition %d, and offset %d", + group_name==NULL ? "" : group_name, + lp_type_name==NULL ? "" : lp_type_name, + annotation==NULL ? "" : annotation, + rep_id, offset); +} + +int codes_mapping_get_lp_relative_id( + tw_lpid gid, + int group_wise, + int annotation_wise){ + int group_index, lp_type_index, rep_id, offset; + codes_mapping_get_lp_info(gid, NULL, &group_index, + local_lp_name, &lp_type_index, local_annotation, &rep_id, &offset); + const char * anno = (local_annotation[0]=='\0') ? NULL : local_annotation; + + int group_lp_count = 0; + // if not group_specific, then count up LPs of all preceding groups + if (!group_wise){ + for (int g = 0; g < group_index; g++){ + int lp_count = 0; + const config_lpgroup_t *lpg = &lpconf.lpgroups[g]; + for (int l = 0; l < lpg->lptypes_count; l++){ + const config_lptype_t *lpt = &lpg->lptypes[l]; + if (strcmp(local_lp_name, lpt->name.ptr) == 0){ + // increment the count if we are ignoring annotations, + // both LPs are unannotated, or if the annotations match + if (!annotation_wise || cmp_anno(anno, lpt->anno.ptr)){ + lp_count += lpt->count; + } + } + } + group_lp_count += lp_count * lpg->repetitions; + } + } + // count up LPs within my group occuring before me + // (the loop is necessary because different annotated LPs may exist in the + // same group) + int lp_count = 0; + int lp_pre_count = 0; + for (int l = 0; l < lpconf.lpgroups[group_index].lptypes_count; l++){ + const config_lptype_t *lpt = &lpconf.lpgroups[group_index].lptypes[l]; + if (strcmp(local_lp_name, lpt->name.ptr) == 0){ + if (!annotation_wise || cmp_anno(anno, lpt->anno.ptr)){ + lp_count += lpt->count; + // special case: if we find an LP entry that matches, but is not + // the same entry where the input gid comes from, then increment + // a separate "pre" counter + if (l < lp_type_index){ + lp_pre_count += lpt->count; + } + } + } + } + // now we have the necessary counts + // return lps in groups that came before + + // lps within the group that came before the target LP + return (int) (group_lp_count + (lp_count * rep_id) + lp_pre_count + offset); +} + +tw_lpid codes_mapping_get_lpid_from_relative( + int relative_id, + const char * group_name, + const char * lp_type_name, + const char * annotation, + int annotation_wise){ + // strategy: count up all preceding LPs. When we reach a point where an LP + // type matches, count up the relative ID. When the accumulated relative ID + // matches or surpasses the input, then we've found our LP + int rel_id_count = 0; + tw_lpid gid_count = 0; + for (int g = 0; g < lpconf.lpgroups_count; g++){ + const config_lpgroup_t *lpg = &lpconf.lpgroups[g]; + if (group_name == NULL || strcmp(group_name, lpg->name.ptr) == 0){ + // consider this group for counting + tw_lpid local_gid_count = 0; + int local_rel_id_count = 0; + for (int l = 0; l < lpg->lptypes_count; l++){ + const config_lptype_t *lpt = &lpg->lptypes[l]; + local_gid_count += lpt->count; + if (strcmp(lp_type_name, lpt->name.ptr) == 0 && + (!annotation_wise || cmp_anno(annotation, lpt->anno.ptr))){ + local_rel_id_count += lpt->count; + } + } + // is our relative id within this group? + if (relative_id < rel_id_count + + lpg->repetitions * local_rel_id_count){ + tw_lpid gid = gid_count; + int rem = relative_id - rel_id_count; + int rep = rem / local_rel_id_count; + rem -= (rep * local_rel_id_count); + gid += local_gid_count * rep; + // count up lps listed prior to this entry + for (int l = 0; l < lpg->lptypes_count; l++){ + const config_lptype_t *lpt = &lpg->lptypes[l]; + if ( strcmp(lp_type_name, lpt->name.ptr) == 0 && + (!annotation_wise || + cmp_anno(annotation, lpt->anno.ptr))){ + if (rem < (int) lpt->count){ + return gid + (tw_lpid) rem; + } + else{ + rem -= lpt->count; + } + } + gid += lpt->count; + } + // this shouldn't happen + goto NOT_FOUND; + } + else if (group_name != NULL){ + // immediate error - found the group, but not the id + goto NOT_FOUND; + } + else{ + // increment and move to the next group + rel_id_count += local_rel_id_count * lpg->repetitions; + gid_count += local_gid_count * lpg->repetitions; + } + } + else{ + // just count up the group LPs + tw_lpid local_gid_count = 0; + for (int l = 0; l < lpg->lptypes_count; l++){ + local_gid_count += lpg->lptypes[l].count; + } + gid_count += local_gid_count * lpg->repetitions; + } + } +NOT_FOUND: + tw_error(TW_LOC, "Unable to find LP-ID for ID %d relative to group %s, " + "lp name %s, annotation %s", + relative_id, + group_name == NULL ? "(all)" : group_name, + lp_type_name, + annotation_wise ? annotation : "(all)"); + return 0; // dummy return +} + +void codes_mapping_get_lp_info( + tw_lpid gid, + char * group_name, + int * group_index, + char * lp_type_name, + int * lp_type_index, + char * annotation, + int * rep_id, + int * offset){ + // running total of lp's we've seen so far + tw_lpid id_total = 0; + // for each group + for (int g = 0; g < lpconf.lpgroups_count; g++){ + const config_lpgroup_t *lpg = &lpconf.lpgroups[g]; + tw_lpid num_id_group, num_id_per_rep = 0; + // count up the number of ids in this group + for (int l = 0; l < lpg->lptypes_count; l++){ + num_id_per_rep += lpg->lptypes[l].count; + } + num_id_group = num_id_per_rep * lpg->repetitions; + if (num_id_group+id_total > gid){ + // we've found the group + tw_lpid rem = gid - id_total; + if (group_name != NULL) + strcpy(group_name, lpg->name.ptr); + *group_index = g; + // find repetition within group + *rep_id = (int) (rem / num_id_per_rep); + rem -= num_id_per_rep * (tw_lpid)*rep_id; + num_id_per_rep = 0; + for (int l = 0; l < lpg->lptypes_count; l++){ + const config_lptype_t *lpt = &lpg->lptypes[l]; + if (rem < num_id_per_rep + lpt->count){ + // found the specific LP + if (lp_type_name != NULL) + strcpy(lp_type_name, lpt->name.ptr); + if (annotation != NULL) { + if (lpt->anno.ptr == NULL) + annotation[0] = '\0'; + else + strcpy(annotation, lpt->anno.ptr); + } + *offset = (int) (rem - num_id_per_rep); + *lp_type_index = l; + return; // done + } + else{ + num_id_per_rep += lpg->lptypes[l].count; + } + } + } + else{ + id_total += num_id_group; + } + } + // LP not found + tw_error(TW_LOC, "Unable to find LP info given gid %lu", gid); +} + +void codes_mapping_get_lp_info2( + tw_lpid gid, + char const * * group_name, + char const * * lp_type_name, + char const * * annotation, + int * rep_id, + int * offset) +{ + // running total of lp's we've seen so far + tw_lpid id_total = 0; + // for each group + for (int g = 0; g < lpconf.lpgroups_count; g++){ + const config_lpgroup_t *lpg = &lpconf.lpgroups[g]; + tw_lpid num_id_group, num_id_per_rep = 0; + // count up the number of ids in this group + for (int l = 0; l < lpg->lptypes_count; l++){ + num_id_per_rep += lpg->lptypes[l].count; + } + num_id_group = num_id_per_rep * lpg->repetitions; + if (num_id_group+id_total > gid){ + // we've found the group + tw_lpid rem = gid - id_total; + if (group_name != NULL) + *group_name = lpg->name.ptr; + // find repetition within group + *rep_id = (int) (rem / num_id_per_rep); + rem -= num_id_per_rep * (tw_lpid)*rep_id; + num_id_per_rep = 0; + for (int l = 0; l < lpg->lptypes_count; l++){ + const config_lptype_t *lpt = &lpg->lptypes[l]; + if (rem < num_id_per_rep + lpt->count){ + // found the specific LP + if (lp_type_name != NULL) + *lp_type_name = lpt->name.ptr; + if (annotation != NULL) + *annotation = lpt->anno.ptr; + *offset = (int) (rem - num_id_per_rep); + return; // done + } + else{ + num_id_per_rep += lpg->lptypes[l].count; + } + } + } + else{ + id_total += num_id_group; + } + } + // LP not found + tw_error(TW_LOC, "Unable to find LP info given gid %lu", gid); +} + +/* This function assigns local and global LP Ids to LPs */ +static void codes_mapping_init(void) +{ + int grp_id, lpt_id, rep_id, offset; + tw_lpid ross_gid, ross_lid; /* ross global and local IDs */ + tw_pe * pe; + char lp_type_name[MAX_NAME_LENGTH]; + int nkp_per_pe = g_tw_nkp; + tw_lpid lpid, kpid; + const tw_lptype *lptype; + + /* have 16 kps per pe, this is the optimized configuration for ROSS custom mapping */ + for(kpid = 0; kpid < nkp_per_pe; kpid++) + tw_kp_onpe(kpid, g_tw_pe[0]); + + int lp_start = + g_tw_mynode * lps_per_pe_floor + mini(g_tw_mynode,lps_leftover); + int lp_end = + (g_tw_mynode+1) * lps_per_pe_floor + mini(g_tw_mynode+1,lps_leftover); + + for (lpid = lp_start; lpid < lp_end; lpid++) + { + ross_gid = lpid; + ross_lid = lpid - lp_start; + kpid = ross_lid % g_tw_nkp; + pe = tw_getpe(kpid % g_tw_npe); + codes_mapping_get_lp_info(ross_gid, NULL, &grp_id, lp_type_name, + &lpt_id, NULL, &rep_id, &offset); +#if CODES_MAPPING_DEBUG + printf("lp:%lu --> kp:%lu, pe:%llu\n", ross_gid, kpid, pe->id); +#endif + tw_lp_onpe(ross_lid, pe, ross_gid); + tw_lp_onkp(g_tw_lp[ross_lid], g_tw_kp[kpid]); + lptype = lp_type_lookup(lp_type_name); + if (lptype == NULL) + tw_error(TW_LOC, "could not find LP with type name \"%s\", " + "did you forget to register the LP?\n", lp_type_name); + else + /* sorry, const... */ + tw_lp_settype(ross_lid, (tw_lptype*) lptype); + } + return; +} + +/* This function takes the global LP ID, maps it to the local LP ID and returns the LP + * lps have global and local LP IDs + * global LP IDs are unique across all PEs, local LP IDs are unique within a PE */ +static tw_lp * codes_mapping_to_lp( tw_lpid lpid) +{ + int index = lpid - (g_tw_mynode * lps_per_pe_floor) - + mini(g_tw_mynode, lps_leftover); +// printf("\n global id %d index %d lps_before %d lps_offset %d local index %d ", lpid, index, lps_before, g_tw_mynode, local_index); + return g_tw_lp[index]; +} + +/* This function loads the configuration file and sets up the number of LPs on each PE */ +void codes_mapping_setup_with_seed_offset(int offset) +{ + int grp, lpt, message_size; + int pes = tw_nnodes(); + + lps_per_pe_floor = 0; + for (grp = 0; grp < lpconf.lpgroups_count; grp++) + { + for (lpt = 0; lpt < lpconf.lpgroups[grp].lptypes_count; lpt++) + lps_per_pe_floor += (lpconf.lpgroups[grp].lptypes[lpt].count * lpconf.lpgroups[grp].repetitions); + } + tw_lpid global_nlps = lps_per_pe_floor; + lps_leftover = lps_per_pe_floor % pes; + lps_per_pe_floor /= pes; + //printf("\n LPs for this PE are %d reps %d ", lps_per_pe_floor, lpconf.lpgroups[grp].repetitions); + g_tw_mapping=CUSTOM; + g_tw_custom_initial_mapping=&codes_mapping_init; + g_tw_custom_lp_global_to_local_map=&codes_mapping_to_lp; + + // configure mem-factor + int mem_factor_conf; + int rc = configuration_get_value_int(&config, "PARAMS", "pe_mem_factor", NULL, + &mem_factor_conf); + if (rc == 0 && mem_factor_conf > 0) + mem_factor = mem_factor_conf; + + g_tw_events_per_pe = mem_factor * codes_mapping_get_lps_for_pe(); + configuration_get_value_int(&config, "PARAMS", "message_size", NULL, &message_size); + if(!message_size) + { + message_size = 256; + printf("\n Warning: ross message size not defined, resetting it to %d", message_size); + } + + // we increment the number of RNGs used to let codes_local_latency use the + // last one + g_tw_nRNG_per_lp++; + + tw_define_lps(codes_mapping_get_lps_for_pe(), message_size); + + // use a similar computation to codes_mapping_init to compute the lpids and + // offsets to use in tw_rand_initial_seed + // an "offset" of 0 reverts to default RNG seeding behavior - see + // ross/rand-clcg4.c for the specific computation + // an "offset" < 0 is ignored + if (offset > 0){ + for (tw_lpid l = 0; l < g_tw_nlp; l++){ + for (int i = 0; i < g_tw_nRNG_per_lp; i++){ + tw_rand_initial_seed(&g_tw_lp[l]->rng[i], (g_tw_lp[l]->gid + + global_nlps * offset) * g_tw_nRNG_per_lp + i); + } + } + } +} + +void codes_mapping_setup(){ + codes_mapping_setup_with_seed_offset(0); +} + +/* given the group and LP type name, return the annotation (or NULL) */ +const char* codes_mapping_get_annotation_by_name( + const char * group_name, + const char * lp_type_name){ + for (int g = 0; g < lpconf.lpgroups_count; g++){ + const config_lpgroup_t *lpg = &lpconf.lpgroups[g]; + if (strcmp(lpg->name.ptr, group_name) == 0){ + // group found, iterate through types + for (int l = 0; l < lpg->lptypes_count; l++){ + const config_lptype_t *lpt = &lpg->lptypes[l]; + if (strcmp(lpt->name.ptr, lp_type_name) == 0){ + // type found, return the annotation + return lpt->anno.ptr; + } + } + } + } + tw_error(TW_LOC, "unable to find annotation using " + "group \"%s\" and lp_type_name \"%s\"", group_name, lp_type_name); + return NULL; +} + +const char* codes_mapping_get_annotation_by_lpid(tw_lpid gid){ + int group_index, lp_type_index, dummy; + codes_mapping_get_lp_info(gid, NULL, &group_index, NULL, &lp_type_index, + NULL, &dummy, &dummy); + return lpconf.lpgroups[group_index].lptypes[lp_type_index].anno.ptr; +} + +/* + * Returns a mapping of LP name to all annotations used with the type + * + * lp_name - lp name as used in the configuration + */ +const config_anno_map_t * +codes_mapping_get_lp_anno_map(const char *lp_name){ + for (uint64_t i = 0; i < lpconf.lpannos_count; i++){ + if (strcmp(lp_name, lpconf.lpannos[i].lp_name.ptr) == 0){ + return &lpconf.lpannos[i]; + } + } + return NULL; +} + +static int get_cid_by_name( + char const * name, + char const * * names, + int num_names) +{ + for (int i = 0; i < num_names; i++) + if (strcmp(name, names[i]) == 0) + return i; + return -1; +} + +static char const * get_name_by_cid( + int cid, + char const * * names, + int num_names) +{ + if (cid < 0 || cid >= num_names) + return NULL; + else + return names[cid]; +} + + +int codes_mapping_get_group_cid_by_name(char const * group_name) +{ + return get_cid_by_name(group_name, lpconf.group_names, + lpconf.lpgroups_count); +} + +int codes_mapping_get_group_cid_by_lpid(tw_lpid id) +{ + char group_name[MAX_NAME_LENGTH]; + int ignore; + codes_mapping_get_lp_info(id, group_name, &ignore, NULL, &ignore, NULL, + &ignore, &ignore); + return codes_mapping_get_group_cid_by_name(group_name); +} + +char const * codes_mapping_get_group_name_by_cid(int cid) +{ + return get_name_by_cid(cid, lpconf.group_names, lpconf.lpgroups_count); +} + +int codes_mapping_get_lp_cid_by_name(char const * lp_type_name) +{ + return get_cid_by_name(lp_type_name, lpconf.lp_names, + lpconf.num_uniq_lptypes); +} + +int codes_mapping_get_lp_cid_by_lpid(tw_lpid id) +{ + char lp_name[MAX_NAME_LENGTH]; + int ignore; + codes_mapping_get_lp_info(id, NULL, &ignore, lp_name, &ignore, NULL, + &ignore, &ignore); + return codes_mapping_get_lp_cid_by_name(lp_name); +} + +char const * codes_mapping_get_lp_name_by_cid(int cid) +{ + return get_name_by_cid(cid, lpconf.lp_names, lpconf.num_uniq_lptypes); +} + +int codes_mapping_get_anno_cid_by_name(char const * annotation) +{ + if (annotation == NULL || annotation[0] == '\0') + return lpconf.num_uniq_annos; + else + return get_cid_by_name(annotation, lpconf.anno_names, + lpconf.num_uniq_annos); +} + +int codes_mapping_get_anno_cid_by_lpid(tw_lpid id) +{ + char anno[MAX_NAME_LENGTH]; + int ignore; + codes_mapping_get_lp_info(id, NULL, &ignore, NULL, &ignore, anno, + &ignore, &ignore); + return codes_mapping_get_anno_cid_by_name(anno); +} + +char const * codes_mapping_get_anno_name_by_cid(int cid) +{ + return get_name_by_cid(cid, lpconf.anno_names, lpconf.num_uniq_annos); +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/util/jobmap-impl/jobmap-dummy.c b/src/util/jobmap-impl/jobmap-dummy.c new file mode 100644 index 0000000000000000000000000000000000000000..9a313c618fdbf9b751dec537e8b49393979eccd3 --- /dev/null +++ b/src/util/jobmap-impl/jobmap-dummy.c @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2015 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include +#include + +#include "src/util/codes-jobmap-method-impl.h" + +static int jobmap_dummy_configure(void const * params, void ** ctx) +{ + int *num_jobs = malloc(sizeof(*num_jobs)); + assert(num_jobs); + *ctx = num_jobs; + + struct codes_jobmap_params_dummy const * p = params; + + *num_jobs = p->num_jobs; + + return 0; +} + +static void jobmap_dummy_destroy(void * ctx) +{ + free(ctx); +} + + +static struct codes_jobmap_id jobmap_dummy_to_local(int id, void const * ctx) +{ + int const * num_jobs = ctx; + struct codes_jobmap_id rtn; + + if (id < *num_jobs) { + rtn.job = id; + rtn.rank = 0; + } + else { + rtn.job = -1; + rtn.rank = -1; + } + + return rtn; +} + +static int jobmap_dummy_to_global(struct codes_jobmap_id id, void const * ctx) +{ + int const * num_jobs = ctx; + + if (id.job < *num_jobs) + return id.job; + else + return -1; +} + +static int jobmap_dummy_get_num_jobs(void const * ctx) +{ + return *(int const *) ctx; +} + +int jobmap_dummy_get_num_ranks(int job_id, void const * ctx) +{ + int num_jobs = *(int const *) ctx; + if (job_id < 0 || job_id >= num_jobs) + return -1; + else + return 1; +} + +struct codes_jobmap_impl jobmap_dummy_impl = { + jobmap_dummy_configure, + jobmap_dummy_destroy, + jobmap_dummy_to_local, + jobmap_dummy_to_global, + jobmap_dummy_get_num_jobs, + jobmap_dummy_get_num_ranks +}; + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/util/jobmap-impl/jobmap-identity.c b/src/util/jobmap-impl/jobmap-identity.c new file mode 100644 index 0000000000000000000000000000000000000000..f99770d55c189a901ed42b211c4f55e70542d5b9 --- /dev/null +++ b/src/util/jobmap-impl/jobmap-identity.c @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2015 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include +#include + +#include "../codes-jobmap-method-impl.h" + +static int jobmap_identity_configure(void const * params, void ** ctx) +{ + int *num_ranks = malloc(sizeof(*num_ranks)); + assert(num_ranks); + *ctx = num_ranks; + + struct codes_jobmap_params_identity const * p = params; + + *num_ranks = p->num_ranks; + + return 0; +} + +static void jobmap_identity_destroy(void * ctx) +{ + free(ctx); +} + +static struct codes_jobmap_id jobmap_identity_to_local(int id, void const * ctx) +{ + int const * num_ranks = ctx; + struct codes_jobmap_id rtn; + + if (id < 0 || id >= *num_ranks) { + rtn.job = -1; + rtn.rank = -1; + } + else { + rtn.job = 0; + rtn.rank = id; + } + + return rtn; +} + +static int jobmap_identity_to_global(struct codes_jobmap_id id, void const * ctx) +{ + int const * num_ranks = ctx; + + if (id.job >= 1 || id.rank >= *num_ranks || id.job < 0 || id.rank < 0) + return -1; + else + return id.rank; +} + +int jobmap_identity_get_num_jobs(void const * ctx) +{ + return 1; +} + +int jobmap_identity_get_num_ranks(int job_id, void const * ctx) +{ + return (job_id == 0) ? *(int const *) ctx : -1; +} + +struct codes_jobmap_impl jobmap_identity_impl = { + jobmap_identity_configure, + jobmap_identity_destroy, + jobmap_identity_to_local, + jobmap_identity_to_global, + jobmap_identity_get_num_jobs, + jobmap_identity_get_num_ranks +}; + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/util/jobmap-impl/jobmap-list.c b/src/util/jobmap-impl/jobmap-list.c new file mode 100644 index 0000000000000000000000000000000000000000..7876727f229a7363cbfe68c67c2298b545d20566 --- /dev/null +++ b/src/util/jobmap-impl/jobmap-list.c @@ -0,0 +1,245 @@ +/* + * Copyright (C) 2015 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ +#include +#include +#include +#include +#include "../codes-jobmap-method-impl.h" + +#define LIST_DEBUG 0 +#define dprintf(_fmt, ...) \ + do { \ + if (LIST_DEBUG) { \ + fprintf(stdout, "jobmap-list: "); \ + fprintf(stdout, _fmt, ##__VA_ARGS__); \ + } \ + } while (0) + +#define ERR(str, ...)\ + do{\ + if (LIST_DEBUG) { \ + fprintf(stderr, "ERROR at %s:%d: " str "\n", \ + __FILE__, __LINE__, ##__VA_ARGS__);\ + } \ + return -1; \ + }while(0) + +struct jobmap_list { + int num_jobs; + int *rank_counts; + int **global_ids; +}; + +#define COND_REALLOC(_len_expr, _cap_var, _buf_var) \ + do { \ + if ((_len_expr) == _cap_var) { \ + _buf_var = realloc(_buf_var, (_cap_var)*2*sizeof(*(_buf_var))); \ + assert(_buf_var); \ + _cap_var *= 2; \ + } \ + } while (0) + +static int parse_line( + FILE *f, + char **line_buf, + int *line_cap, + int *num_ranks, + int **rank_list) +{ + char * buf = *line_buf; + + int cap = *line_cap; + int pos = 0; + + *num_ranks = 0; + + for (int c = fgetc(f); c != EOF && c != '\n'; c = fgetc(f)) { + buf[pos++] = (char)c; + COND_REALLOC(pos, cap, buf); + } + if (ferror(f)) { + *num_ranks = -1; + goto end; + } + else { + buf[pos]='\0'; + } + + int list_cap = 8; + int *lst = malloc(list_cap * sizeof(*lst)); + assert(lst); + int rank; + + *num_ranks = 0; + for (char * tok = strtok(buf, " \t\r"); tok != NULL; + tok = strtok(NULL, " \t\r")) { + int rc = sscanf(tok, "%d", &rank); + if (rc != 1) { + fprintf(stderr, + "jobmap-list: unable to read alloc file - bad rank (%s)\n", + tok); + *num_ranks = -1; + break; + } + COND_REALLOC(*num_ranks, list_cap, lst); + lst[*num_ranks] = rank; + *num_ranks += 1; + } + + if (*num_ranks <= 0) { + *rank_list = NULL; + free(lst); + } + else + *rank_list = lst; +end: + *line_buf = buf; + *line_cap = cap; + return (*num_ranks < 0) ? -1 : 0; +} + +static int jobmap_list_configure(void const * params, void ** ctx) +{ + struct codes_jobmap_params_list const * p = params; + struct jobmap_list *lst = malloc(sizeof(*lst)); + assert(lst); + + FILE *f = fopen(p->alloc_file, "r"); + if(!f) { + ERR("Could not open file %s", p->alloc_file); + } + + // job storage + lst->num_jobs = 0; + int job_cap = 8; + lst->rank_counts = calloc(job_cap, sizeof(*lst->rank_counts)); + assert(lst->rank_counts); + lst->global_ids = calloc(job_cap, sizeof(*lst->global_ids)); + assert(lst->global_ids); + + // line storage + int line_cap = 1<<10; + char *line_buf = malloc(line_cap); + assert(line_buf); + + int rc = 0; + do { + rc = parse_line(f, &line_buf, &line_cap, + &lst->rank_counts[lst->num_jobs], + &lst->global_ids[lst->num_jobs]); + if (rc == -1) { + // error and exit + if (ferror(f)) { + perror("fgets"); + break; + } + } + else if (lst->rank_counts[lst->num_jobs] > 0) { + lst->num_jobs++; + } + // resize if needed + if (!feof(f) && lst->num_jobs == job_cap) { + int tmp = job_cap; + COND_REALLOC(lst->num_jobs, tmp, lst->rank_counts); + COND_REALLOC(lst->num_jobs, job_cap, lst->global_ids); + } + } while (!feof(f)); + + if (rc == 0) { + fclose(f); + free(line_buf); + *ctx = lst; + return 0; + } + else { + for (int i = 0; i < job_cap; i++) { + free(lst->global_ids[i]); + } + free(lst->global_ids); + free(lst->rank_counts); + free(lst); + *ctx = NULL; + return -1; + } +} + +static struct codes_jobmap_id jobmap_list_to_local(int id, void const * ctx) +{ + struct codes_jobmap_id rtn; + rtn.job = -1; + rtn.rank = -1; + + struct jobmap_list const *lst = (struct jobmap_list const *)ctx; + + for(int i=0; inum_jobs; i++) { + for(int j=0; j < lst->rank_counts[i]; j++) { + if(id == lst->global_ids[i][j]) { + rtn.job = i; + rtn.rank = j; + return rtn; + } + } + } + + return rtn; +} + +static int jobmap_list_to_global(struct codes_jobmap_id id, void const * ctx) +{ + struct jobmap_list const *lst = (struct jobmap_list*)ctx; + + if (id.job < lst->num_jobs) + return lst->global_ids[id.job][id.rank]; + else + return -1; +} + +static int jobmap_list_get_num_jobs(void const * ctx) +{ + struct jobmap_list *lst = (struct jobmap_list*)ctx; + return lst->num_jobs; +} + +static int jobmap_list_get_num_ranks(int job_id, void const * ctx) +{ + struct jobmap_list const *lst = (struct jobmap_list const *) ctx; + if (job_id < 0 || job_id >= lst->num_jobs) + return -1; + else + return lst->rank_counts[job_id]; +} + +static void jobmap_list_destroy(void * ctx) +{ + struct jobmap_list *lst = (struct jobmap_list*)ctx; + for(int i=0; inum_jobs; i++){ + free(lst->global_ids[i]); + } + + free(lst->global_ids); + free(lst->rank_counts); + free(ctx); +} + + +struct codes_jobmap_impl jobmap_list_impl = { + jobmap_list_configure, + jobmap_list_destroy, + jobmap_list_to_local, + jobmap_list_to_global, + jobmap_list_get_num_jobs, + jobmap_list_get_num_ranks +}; + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/util/local-storage-model.c b/src/util/local-storage-model.c new file mode 100644 index 0000000000000000000000000000000000000000..88863ec0cd25dbcb442fca7d4575177aacb364b3 --- /dev/null +++ b/src/util/local-storage-model.c @@ -0,0 +1,930 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CATEGORY_NAME_MAX 16 +#define CATEGORY_MAX 12 + +int lsm_in_sequence = 0; +tw_stime lsm_msg_offset = 0.0; + +/* holds statistics about disk traffic on each LP */ +typedef struct lsm_stats_s +{ + char category[CATEGORY_NAME_MAX]; + long read_count; + long read_bytes; + long read_seeks; + tw_stime read_time; + long write_count; + long write_bytes; + long write_seeks; + tw_stime write_time; +} lsm_stats_t; + +/* + * disk model parameters + */ +typedef struct disk_model_s +{ + unsigned int *request_sizes; + double *write_rates; + double *read_rates; + double *write_overheads; + double *read_overheads; + double *write_seeks; + double *read_seeks; + unsigned int bins; + // sched params + // 0 - no scheduling + // >0 - make scheduler with use_sched priority lanes + int use_sched; +} disk_model_t; + +/* + * lsm_message_data_t + * - data used for input in transfer time calculation + * - data comes for caller + * - object: id of byte stream which could be a file, object, etc. + * - offset: offset into byte stream + * - size: size in bytes of request + */ +typedef struct lsm_message_data_s +{ + uint64_t object; + uint64_t offset; + uint64_t size; + char category[CATEGORY_NAME_MAX]; /* category for traffic */ + int prio; // for scheduling +} lsm_message_data_t; + +/* + * lsm_sched_op_s - operation to be scheduled + */ +typedef struct lsm_sched_op_s +{ + lsm_message_data_t data; + struct qlist_head ql; +} lsm_sched_op_t; + +/* + * lsm_sched_s - data structure for implementing scheduling loop + */ +typedef struct lsm_sched_s +{ + int num_prios; + // number of pending requests, incremented on new and decremented on + // complete + int active_count; + // scheduler mallocs data per-request - hold onto and free later + struct rc_stack *freelist; + struct qlist_head *queues; +} lsm_sched_t; + +/* + * lsm_state_s + * - state tracking structure for each LP node + * - next_idle: next point in time the disk will be idle + * - model: disk parameters + * - current_offset: last offset the disk operated on + * - current_object: last object id that operated on + */ +typedef struct lsm_state_s +{ + tw_stime next_idle; + disk_model_t *model; + int64_t current_offset; + uint64_t current_object; + lsm_stats_t lsm_stats_array[CATEGORY_MAX]; + /* scheduling state */ + int use_sched; + lsm_sched_t sched; +} lsm_state_t; + +/* + * lsm_message_t + * - holds event data + * - event: event type + * - data: IO request data + * - wrap: wrapped event data of caller + */ +typedef struct lsm_message_s +{ + int magic; /* magic number */ + lsm_event_t event; + int prio; // op priority (user-set on request, used by LSM in rc for complete) + tw_stime prev_idle; + lsm_stats_t prev_stat; + int64_t prev_offset; + uint64_t prev_object; + lsm_message_data_t data; + struct codes_cb_params cb; +} lsm_message_t; + +/* + * Prototypes + */ +static void lsm_lp_init (lsm_state_t *ns, tw_lp *lp); +static void lsm_event (lsm_state_t *ns, tw_bf *b, lsm_message_t *m, tw_lp *lp); +static void lsm_rev_event (lsm_state_t *ns, tw_bf *b, lsm_message_t *m, tw_lp *lp); +static void lsm_finalize (lsm_state_t *ns, tw_lp *lp); +static void handle_io_sched_new(lsm_state_t *ns, tw_bf *b, lsm_message_t *m_in, tw_lp *lp); +static void handle_rev_io_sched_new(lsm_state_t *ns, tw_bf *b, lsm_message_t *m_in, tw_lp *lp); +static void handle_io_request(lsm_state_t *ns, tw_bf *b, lsm_message_data_t *data, lsm_message_t *m_in, tw_lp *lp); +static void handle_rev_io_request(lsm_state_t *ns, tw_bf *b, lsm_message_data_t *data, lsm_message_t *m_in, tw_lp *lp); +static void handle_io_sched_compl(lsm_state_t *ns, tw_bf *b, lsm_message_t *m_in, tw_lp *lp); +static void handle_rev_io_sched_compl(lsm_state_t *ns, tw_bf *b, lsm_message_t *m_in, tw_lp *lp); +static void handle_io_completion (lsm_state_t *ns, tw_bf *b, lsm_message_t *m_in, tw_lp *lp); +static void handle_rev_io_completion (lsm_state_t *ns, tw_bf *b, lsm_message_t *m_in, tw_lp *lp); +static lsm_stats_t *find_stats(const char* category, lsm_state_t *ns); +static void write_stats(tw_lp* lp, lsm_stats_t* stat); + +/* + * Globals + */ + +static int lsm_magic = 0; + +/* configuration parameters (by annotation) */ +static disk_model_t model_unanno, *models_anno = NULL; +static const config_anno_map_t *anno_map = NULL; + +/* sched temporary for lsm_set_event_priority */ +static int temp_prio = -1; + +/* + * lsm_lp + * - implements ROSS callback interfaces + */ +tw_lptype lsm_lp = +{ + (init_f) lsm_lp_init, + (pre_run_f) NULL, + (event_f) lsm_event, + (revent_f) lsm_rev_event, + (final_f) lsm_finalize, + (map_f) codes_mapping, + sizeof(lsm_state_t) +}; + +static tw_stime transfer_time_table (lsm_state_t *ns, + lsm_stats_t *stat, + int rw, + uint64_t object, + int64_t offset, + uint64_t size) +{ + double mb; + double time = 0.0; + double disk_rate; + double disk_seek; + double disk_overhead; + int i; + + /* find nearest size rounded down. */ + for (i = 0; i < ns->model->bins; i++) + { + if (ns->model->request_sizes[i] > size) + { + break; + } + } + if (i > 0) i--; + + if (rw) + { + /* read */ + disk_rate = ns->model->read_rates[i]; + disk_seek = ns->model->read_seeks[i]; + disk_overhead = ns->model->read_overheads[i]; + } + else + { + /* write */ + disk_rate = ns->model->write_rates[i]; + disk_seek = ns->model->write_seeks[i]; + disk_overhead = ns->model->write_overheads[i]; + + } + + /* transfer time */ + mb = ((double)size) / (1024.0 * 1024.0); + time += (mb / disk_rate) * 1000.0 * 1000.0 * 1000.0; + + /* request overhead */ + time += (disk_overhead * 1000.0); + + /* seek */ + if ((object != ns->current_object) || + (offset < ns->current_offset) || + (offset > (ns->current_offset+512))) + { + if (rw) stat->read_seeks++; else stat->write_seeks++; + time += (disk_seek * 1000.0); + } + + + /* update statistics */ + if (rw) + { + stat->read_count += 1; + stat->read_bytes += size; + stat->read_time += time; + } + else + { + stat->write_count += 1; + stat->write_bytes += size; + stat->write_time += time; + } + + return time; +} + +void lsm_io_event_rc(tw_lp *sender) +{ + codes_local_latency_reverse(sender); +} + +tw_lpid lsm_find_local_device( + struct codes_mctx const * map_ctx, + tw_lpid sender_gid) +{ + return codes_mctx_to_lpid(map_ctx, LSM_NAME, sender_gid); +} + +void lsm_io_event( + const char * lp_io_category, + uint64_t io_object, + int64_t io_offset, + uint64_t io_size_bytes, + int io_type, + tw_stime delay, + tw_lp *sender, + struct codes_mctx const * map_ctx, + int return_tag, + msg_header const * return_header, + struct codes_cb_info const * cb) +{ + assert(strlen(lp_io_category) < CATEGORY_NAME_MAX-1); + assert(strlen(lp_io_category) > 0); + SANITY_CHECK_CB(cb, lsm_return_t); + + tw_lpid lsm_id = codes_mctx_to_lpid(map_ctx, LSM_NAME, sender->gid); + + tw_stime delta = delay + codes_local_latency(sender); + if (lsm_in_sequence) { + tw_stime tmp = lsm_msg_offset; + lsm_msg_offset += delta; + delta += tmp; + } + + tw_event *e = tw_event_new(lsm_id, delta, sender); + lsm_message_t *m = tw_event_data(e); + m->magic = lsm_magic; + m->event = (lsm_event_t) io_type; + m->data.object = io_object; + m->data.offset = io_offset; + m->data.size = io_size_bytes; + strcpy(m->data.category, lp_io_category); + + // get the priority count for checking + int num_prios = lsm_get_num_priorities(map_ctx, sender->gid); + // prio checks and sets + if (num_prios <= 0) // disabled scheduler - ignore + m->data.prio = 0; + else if (temp_prio < 0) // unprovided priority - defer to max possible + m->data.prio = num_prios-1; + else if (temp_prio < num_prios) // valid priority + m->data.prio = temp_prio; + else + tw_error(TW_LOC, + "LP %lu, LSM LP %lu: Bad priority (%d supplied, %d lanes)\n", + sender->gid, lsm_id, temp_prio, num_prios); + // reset temp_prio + temp_prio = -1; + + m->cb.info = *cb; + m->cb.h = *return_header; + m->cb.tag = return_tag; + + tw_event_send(e); +} + +int lsm_get_num_priorities( + struct codes_mctx const * map_ctx, + tw_lpid sender_id) +{ + char const * annotation = + codes_mctx_get_annotation(map_ctx, LSM_NAME, sender_id); + + if (annotation == NULL) { + assert(anno_map->has_unanno_lp); + return model_unanno.use_sched; + } + else { + for (int i = 0; i < anno_map->num_annos; i++) { + if (strcmp(anno_map->annotations[i].ptr, annotation) == 0) + return models_anno[i].use_sched; + } + assert(0); + return -1; + } +} + +void lsm_set_event_priority(int prio) +{ + temp_prio = prio; +} + +/* + * lsm_lp_init + * - initialize the lsm model + * - sets the disk to be idle now + */ +static void lsm_lp_init (lsm_state_t *ns, tw_lp *lp) +{ + memset(ns, 0, sizeof(*ns)); + + ns->next_idle = tw_now(lp); + + // set the correct model + const char *anno = codes_mapping_get_annotation_by_lpid(lp->gid); + if (anno == NULL) + ns->model = &model_unanno; + else { + int id = configuration_get_annotation_index(anno, anno_map); + ns->model = &models_anno[id]; + } + + // initialize the scheduler if need be + ns->use_sched = ns->model->use_sched > 0; + if (ns->use_sched) { + ns->sched.num_prios = ns->model->use_sched; + ns->sched.active_count = 0; + rc_stack_create(&ns->sched.freelist); + ns->sched.queues = + malloc(ns->sched.num_prios * sizeof(*ns->sched.queues)); + for (int i = 0; i < ns->sched.num_prios; i++) + INIT_QLIST_HEAD(&ns->sched.queues[i]); + } + + return; +} + +/* + * lsm_event + * - event handler callback + * - dispatches the events to the appropriate handlers + * - handles initializtion of node state + */ +static void lsm_event (lsm_state_t *ns, tw_bf *b, lsm_message_t *m, tw_lp *lp) +{ + assert(m->magic == lsm_magic); + + switch (m->event) + { + case LSM_WRITE_REQUEST: + case LSM_READ_REQUEST: + if (LSM_DEBUG) + printf("svr(%llu): REQUEST obj:%llu off:%llu size:%llu\n", + (unsigned long long)lp->gid, + (unsigned long long)m->data.object, + (unsigned long long)m->data.offset, + (unsigned long long)m->data.size); + assert(ns->model); + if (ns->use_sched) + handle_io_sched_new(ns, b, m, lp); + else + handle_io_request(ns, b, &m->data, m, lp); + break; + case LSM_WRITE_COMPLETION: + case LSM_READ_COMPLETION: + if (LSM_DEBUG) + printf("svr(%llu): COMPLETION\n", + (unsigned long long)lp->gid); + handle_io_completion(ns, b, m, lp); + break; + default: + printf("svr(%llu): Unknown Event:%d\n", + (unsigned long long)lp->gid, + m->event); + break; + } + + return; +} + +/* + * lsm_rev_event + * - callback to reverse an event + */ +static void lsm_rev_event(lsm_state_t *ns, + tw_bf *b, + lsm_message_t *m, + tw_lp *lp) +{ + assert(m->magic == lsm_magic); + + switch (m->event) + { + case LSM_WRITE_REQUEST: + case LSM_READ_REQUEST: + if (LSM_DEBUG) + printf("svr(%llu): reverse REQUEST obj:%llu off:%llu size:%llu\n", + (unsigned long long)lp->gid, + (unsigned long long)m->data.object, + (unsigned long long)m->data.offset, + (unsigned long long)m->data.size); + if (ns->use_sched) + handle_rev_io_sched_new(ns, b, m, lp); + else + handle_rev_io_request(ns, b, &m->data, m, lp); + break; + case LSM_WRITE_COMPLETION: + case LSM_READ_COMPLETION: + if (LSM_DEBUG) + printf("svr(%llu): reverse COMPLETION\n", + (unsigned long long)lp->gid); + handle_rev_io_completion(ns, b, m, lp); + break; + default: + printf("svr(%llu): reverse Unknown Event:%d\n", + (unsigned long long)lp->gid, + m->event); + break; + } + + return; +} + +/* + * lsm_finalize + * - callback to release model resources + */ +static void lsm_finalize(lsm_state_t *ns, + tw_lp *lp) +{ + int i; + lsm_stats_t all; + + memset(&all, 0, sizeof(all)); + sprintf(all.category, "all"); + + for(i=0; ilsm_stats_array[i].category) > 0) + { + all.write_count += ns->lsm_stats_array[i].write_count; + all.write_bytes += ns->lsm_stats_array[i].write_bytes; + all.write_time += ns->lsm_stats_array[i].write_time; + all.write_seeks += ns->lsm_stats_array[i].write_seeks; + all.read_count += ns->lsm_stats_array[i].read_count; + all.read_bytes += ns->lsm_stats_array[i].read_bytes; + all.read_seeks += ns->lsm_stats_array[i].read_seeks; + all.read_time += ns->lsm_stats_array[i].read_time; + + write_stats(lp, &ns->lsm_stats_array[i]); + } + } + + write_stats(lp, &all); + + return; +} + +static void handle_io_sched_new( + lsm_state_t *ns, + tw_bf *b, + lsm_message_t *m_in, + tw_lp *lp) +{ + if (LSM_DEBUG) + printf("handle_io_sched_new called\n"); + // if nothing else is going on, then issue directly + if (!ns->sched.active_count) + handle_io_request(ns, b, &m_in->data, m_in, lp); + else { + lsm_sched_op_t *op = malloc(sizeof(*op)); + op->data = m_in->data; + qlist_add_tail(&op->ql, &ns->sched.queues[m_in->prio]); + } + ns->sched.active_count++; +} + +static void handle_rev_io_sched_new( + lsm_state_t *ns, + tw_bf *b, + lsm_message_t *m_in, + tw_lp *lp) +{ + if (LSM_DEBUG) + printf("handle_rev_io_sched_new called\n"); + ns->sched.active_count--; + if (!ns->sched.active_count) + handle_rev_io_request(ns, b, &m_in->data, m_in, lp); + else { + struct qlist_head *ent = qlist_pop_back(&ns->sched.queues[m_in->prio]); + assert(ent); + lsm_sched_op_t *op = qlist_entry(ent, lsm_sched_op_t, ql); + free(op); + } +} + +static void handle_io_sched_compl( + lsm_state_t *ns, + tw_bf *b, + lsm_message_t *m_in, + tw_lp *lp) +{ + if (LSM_DEBUG) + printf("handle_io_sched_compl called\n"); + ns->sched.active_count--; + if (ns->sched.active_count) { + lsm_sched_op_t *next = NULL; + struct qlist_head *ent = NULL; + for (int i = 0; i < ns->sched.num_prios; i++) { + ent = qlist_pop(&ns->sched.queues[i]); + if (ent != NULL) { + next = qlist_entry(ent, lsm_sched_op_t, ql); + m_in->prio = i; + break; + } + } + assert(next); + handle_io_request(ns, b, &next->data, m_in, lp); + // now done with this request metadata + rc_stack_push(lp, next, free, ns->sched.freelist); + } +} + +static void handle_rev_io_sched_compl( + lsm_state_t *ns, + tw_bf *b, + lsm_message_t *m_in, + tw_lp *lp) +{ + if (LSM_DEBUG) + printf("handle_rev_io_sched_compl called\n"); + if (ns->sched.active_count) { + lsm_sched_op_t *prev = rc_stack_pop(ns->sched.freelist); + handle_rev_io_request(ns, b, &prev->data, m_in, lp); + qlist_add_tail(&prev->ql, &ns->sched.queues[m_in->prio]); + } + ns->sched.active_count++; +} + + +/* + * handle_io_request + * - handles the IO request events + * - computes the next_idle time + * - fires disk completion event at computed time + */ +static void handle_io_request(lsm_state_t *ns, + tw_bf *b, + lsm_message_data_t *data, + lsm_message_t *m_in, + tw_lp *lp) +{ + tw_stime queue_time, t_time; + tw_event *e; + lsm_message_t *m_out; + lsm_stats_t *stat; + int rw = (m_in->event == LSM_READ_REQUEST) ? 1 : 0; + + tw_stime (*transfer_time) (lsm_state_t *, lsm_stats_t *, int, uint64_t, int64_t, uint64_t); + + transfer_time = transfer_time_table; + + stat = find_stats(data->category, ns); + + /* save history for reverse operation */ + m_in->prev_idle = ns->next_idle; + m_in->prev_stat = *stat; + m_in->prev_object = ns->current_object; + m_in->prev_offset = ns->current_offset; + + if (ns->next_idle > tw_now(lp)) + { + queue_time = ns->next_idle - tw_now(lp); + } + else + { + queue_time = 0; + } + + + t_time = transfer_time(ns, + stat, + rw, + data->object, + data->offset, + data->size); + queue_time += t_time; + ns->next_idle = queue_time + tw_now(lp); + ns->current_offset = data->offset + data->size; + ns->current_object = data->object; + + e = tw_event_new(lp->gid, queue_time, lp); + m_out = (lsm_message_t*)tw_event_data(e); + + memcpy(m_out, m_in, sizeof(*m_in)); + if (m_out->event == LSM_WRITE_REQUEST) + { + m_out->event = LSM_WRITE_COMPLETION; + } + else + { + m_out->event = LSM_READ_COMPLETION; + } + + m_out->prio = m_in->prio; + + tw_event_send(e); + + return; +} + + +/* + * handle_rev_io_request + * - handle reversing the io request + */ +static void handle_rev_io_request(lsm_state_t *ns, + tw_bf *b, + lsm_message_data_t *data, + lsm_message_t *m_in, + tw_lp *lp) +{ + lsm_stats_t *stat; + + stat = find_stats(data->category, ns); + + ns->next_idle = m_in->prev_idle; + *stat = m_in->prev_stat; + ns->current_object = m_in->prev_object; + ns->current_offset = m_in->prev_offset; + + return; +} + +/* + * handle_io_completion + * - handle IO completion events + * - invoke the callers original completion event + */ +static void handle_io_completion (lsm_state_t *ns, + tw_bf *b, + lsm_message_t *m_in, + tw_lp *lp) +{ + SANITY_CHECK_CB(&m_in->cb.info, lsm_return_t); + + tw_event * e = tw_event_new(m_in->cb.h.src, codes_local_latency(lp), lp); + void * m = tw_event_data(e); + + GET_INIT_CB_PTRS(&m_in->cb, m, lp->gid, h, tag, rc, lsm_return_t); + + /* no failures to speak of yet */ + rc->rc = 0; + + tw_event_send(e); + + // continue the loop + if (ns->use_sched) + handle_io_sched_compl(ns, b, m_in, lp); + + return; +} + +/* + * handle_rev_io_completion + * - reverse io completion event + * - currently nothing to do in this case + */ +static void handle_rev_io_completion (lsm_state_t *ns, + tw_bf *b, + lsm_message_t *m_in, + tw_lp *lp) +{ + if (ns->use_sched) + handle_rev_io_sched_compl(ns, b, m_in, lp); + + codes_local_latency_reverse(lp); + return; +} + +static lsm_stats_t *find_stats(const char* category, lsm_state_t *ns) +{ + int i; + int new_flag = 0; + int found_flag = 0; + + for(i=0; ilsm_stats_array[i].category) == 0) + { + found_flag = 1; + new_flag = 1; + break; + } + if(strcmp(category, ns->lsm_stats_array[i].category) == 0) + { + found_flag = 1; + new_flag = 0; + break; + } + } + assert(found_flag); + + if(new_flag) + { + strcpy(ns->lsm_stats_array[i].category, category); + } + return(&ns->lsm_stats_array[i]); + +} + +static void write_stats(tw_lp* lp, lsm_stats_t* stat) +{ + int ret; + char id[32]; + char data[1024]; + + sprintf(id, "lsm-category-%s", stat->category); + sprintf(data, "lp:%ld\twrite_count:%ld\twrite_bytes:%ld\twrite_seeks:%ld\twrite_time:%f\t" + "read_count:%ld\tread_bytes:%ld\tread_seeks:%ld\tread_time:%f\n", + (long)lp->gid, + stat->write_count, + stat->write_bytes, + stat->write_seeks, + stat->write_time, + stat->read_count, + stat->read_bytes, + stat->read_seeks, + stat->read_time); + + ret = lp_io_write(lp->gid, id, strlen(data), data); + assert(ret == 0); + + return; + +} + +void lsm_register(void) +{ + uint32_t h1=0, h2=0; + + bj_hashlittle2("localstorage", strlen("localstorage"), &h1, &h2); + lsm_magic = h1+h2; + + lp_type_register(LSM_NAME, &lsm_lp); +} + +// read the configuration file for a given annotation +static void read_config(ConfigHandle *ch, char const * anno, disk_model_t *model) +{ + char **values; + size_t length; + int rc; + // request sizes + rc = configuration_get_multivalue(ch, LSM_NAME, "request_sizes", anno, + &values,&length); + assert(rc == 1); + model->request_sizes = (unsigned int*)malloc(sizeof(int)*length); + assert(model->request_sizes); + model->bins = length; + for (int i = 0; i < length; i++) + { + model->request_sizes[i] = atoi(values[i]); + } + free(values); + + // write rates + rc = configuration_get_multivalue(ch, LSM_NAME, "write_rates", anno, + &values,&length); + assert(rc == 1); + model->write_rates = (double*)malloc(sizeof(double)*length); + assert(model->write_rates); + assert(length == model->bins); + for (int i = 0; i < length; i++) + { + model->write_rates[i] = strtod(values[i], NULL); + } + free(values); + + // read rates + rc = configuration_get_multivalue(ch, LSM_NAME, "read_rates", anno, + &values,&length); + assert(rc == 1); + model->read_rates = (double*)malloc(sizeof(double)*length); + assert(model->read_rates); + assert(model->bins == length); + for (int i = 0; i < length; i++) + { + model->read_rates[i] = strtod(values[i], NULL); + } + free(values); + + // write overheads + rc = configuration_get_multivalue(ch, LSM_NAME, "write_overheads", anno, + &values,&length); + assert(rc == 1); + model->write_overheads = (double*)malloc(sizeof(double)*length); + assert(model->write_overheads); + assert(model->bins == length); + for (int i = 0; i < length; i++) + { + model->write_overheads[i] = strtod(values[i], NULL); + } + free(values); + + // read overheades + rc = configuration_get_multivalue(ch, LSM_NAME, "read_overheads", anno, + &values,&length); + assert(rc == 1); + model->read_overheads = (double*)malloc(sizeof(double)*length); + assert(model->read_overheads); + assert(model->bins == length); + for (int i = 0; i < length; i++) + { + model->read_overheads[i] = strtod(values[i], NULL); + } + free(values); + + // write seek latency + rc = configuration_get_multivalue(ch, LSM_NAME, "write_seeks", anno, + &values,&length); + assert(rc == 1); + model->write_seeks = (double*)malloc(sizeof(double)*length); + assert(model->write_seeks); + assert(model->bins == length); + for (int i = 0; i < length; i++) + { + model->write_seeks[i] = strtod(values[i], NULL); + } + free(values); + + // read seek latency + rc = configuration_get_multivalue(ch, LSM_NAME, "read_seeks", anno, + &values,&length); + assert(rc == 1); + model->read_seeks = (double*)malloc(sizeof(double)*length); + assert(model->read_seeks); + assert(model->bins == length); + for (int i = 0; i < length; i++) + { + model->read_seeks[i] = strtod(values[i], NULL); + } + free(values); + + // scheduling parameters (this can fail) + configuration_get_value_int(ch, LSM_NAME, "enable_scheduler", anno, + &model->use_sched); + assert(model->use_sched >= 0); +} + +void lsm_configure(void) +{ + /* check and see if any lsm LPs are being used - otherwise, + * skip the config */ + if (0 == codes_mapping_get_lp_count(NULL, 0, LSM_NAME, NULL, 1)) + return; + + anno_map = codes_mapping_get_lp_anno_map(LSM_NAME); + assert(anno_map); + models_anno = (disk_model_t*)malloc(anno_map->num_annos * sizeof(*models_anno)); + + // read the configuration for unannotated entries + if (anno_map->has_unanno_lp > 0){ + read_config(&config, NULL, &model_unanno); + } + + for (uint64_t i = 0; i < anno_map->num_annos; i++){ + char const * anno = anno_map->annotations[i].ptr; + read_config(&config, anno, &models_anno[i]); + } +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ft=c ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/util/lookup3.c b/src/util/lookup3.c new file mode 100644 index 0000000000000000000000000000000000000000..9f9ec9ecf8e2c3f2221b58d4706caa7ee295a71c --- /dev/null +++ b/src/util/lookup3.c @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include "codes_base_config.h" +#include "codes/jenkins-hash.h" + +/* used to prevent address sanitizer from complaining about jenkins hash + * algorithm + */ +#if defined(__clang__) || defined (__GNUC__) +# define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) +#else +# define ATTRIBUTE_NO_SANITIZE_ADDRESS +#endif + +/* +------------------------------------------------------------------------------- +lookup3.c, by Bob Jenkins, May 2006, Public Domain. + +These are functions for producing 32-bit hashes for hash table lookup. +hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() +are externally useful functions. Routines to test the hash are included +if SELF_TEST is defined. You can use this free for any purpose. It's in +the public domain. It has no warranty. + +You probably want to use hashlittle(). hashlittle() and hashbig() +hash byte arrays. hashlittle() is faster than hashbig() on +little-endian machines. Intel and AMD are little-endian machines. +On second thought, you probably want hashlittle2(), which is identical to +hashlittle() except it returns two 32-bit hashes for the price of one. +You could implement hashbig2() if you wanted but I haven't bothered here. + +If you want to find a hash of, say, exactly 7 integers, do + a = i1; b = i2; c = i3; + mix(a,b,c); + a += i4; b += i5; c += i6; + mix(a,b,c); + a += i7; + final(a,b,c); +then use c as the hash value. If you have a variable length array of +4-byte integers to hash, use hashword(). If you have a byte array (like +a character string), use hashlittle(). If you have several byte arrays, or +a mix of things, see the comments above hashlittle(). + +Why is this so big? I read 12 bytes at a time into 3 4-byte integers, +then mix those integers. This is fast (you can do a lot more thorough +mixing with 12*3 instructions on 3 integers than you can with 3 instructions +on 1 byte), but shoehorning those bytes into integers efficiently is messy. +------------------------------------------------------------------------------- +#define SELF_TEST 1 +*/ + +#include /* defines printf for tests */ +#include /* defines time_t for timings in the test */ +#include /* defines uint32_t etc */ +#include /* attempt to define endianness */ +#ifdef linux +# include /* attempt to define endianness */ +#endif + +/* + * My best guess at if you are big-endian or little-endian. This may + * need adjustment. + */ +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) +# define HASH_LITTLE_ENDIAN 1 +# define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 1 +#else +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((uint32_t)1<<(n)) +#define hashmask(n) (hashsize(n)-1) +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +/* +------------------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. + +This is reversible, so any information in (a,b,c) before mix() is +still in (a,b,c) after mix(). + +If four pairs of (a,b,c) inputs are run through mix(), or through +mix() in reverse, there are at least 32 bits of the output that +are sometimes the same for one pair and different for another pair. +This was tested for: +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that +satisfy this are + 4 6 8 16 19 4 + 9 15 3 18 27 15 + 14 9 3 7 17 3 +Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing +for "differ" defined as + with a one-bit base and a two-bit delta. I +used http://burtleburtle.net/bob/hash/avalanche.html to choose +the operations, constants, and arrangements of the variables. + +This does not achieve avalanche. There are input bits of (a,b,c) +that fail to affect some output bits of (a,b,c), especially of a. The +most thoroughly mixed value is c, but it doesn't really even achieve +avalanche in c. + +This allows some parallelism. Read-after-writes are good at doubling +the number of bits affected, so the goal of mixing pulls in the opposite +direction as the goal of parallelism. I did what I could. Rotates +seem to cost as much as shifts on every machine I could lay my hands +on, and rotates are much kinder to the top and bottom bits, so I used +rotates. +------------------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +/* +------------------------------------------------------------------------------- +final -- final mixing of 3 32-bit values (a,b,c) into c + +Pairs of (a,b,c) values differing in only a few bits will usually +produce values of c that look totally different. This was tested for +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +These constants passed: + 14 11 25 16 4 14 24 + 12 14 25 16 4 14 24 +and these came close: + 4 8 15 26 3 22 24 + 10 8 15 26 3 22 24 + 11 8 15 26 3 22 24 +------------------------------------------------------------------------------- +*/ +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + +/* + * hashlittle2: return 2 32-bit hash values + * + * This is identical to hashlittle(), except it returns two 32-bit hash + * values instead of just one. This is good enough for hash table + * lookup with 2^^64 buckets, or if you want a second hash if you're not + * happy with the first, or if you want a probably-unique 64-bit ID for + * the key. *pc is better mixed than *pb, so use *pc first. If you want + * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)". + */ +ATTRIBUTE_NO_SANITIZE_ADDRESS +void bj_hashlittle2( + const void *key, /* the key to hash */ + size_t length, /* length of the key */ + uint32_t *pc, /* IN: primary initval, OUT: primary hash */ + uint32_t *pb) /* IN: secondary initval, OUT: secondary hash */ +{ + uint32_t a,b,c; /* internal state */ + union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)length) + *pc; + c += *pb; + + u.ptr = key; + if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { + const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ +#ifdef VALGRIND + const uint8_t *k8; +#endif + + /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; + case 11: c+=((uint32_t)k[10])<<16; + case 10: c+=((uint32_t)k[9])<<8; + case 9 : c+=k[8]; + case 8 : b+=((uint32_t)k[7])<<24; + case 7 : b+=((uint32_t)k[6])<<16; + case 6 : b+=((uint32_t)k[5])<<8; + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3])<<24; + case 3 : a+=((uint32_t)k[2])<<16; + case 2 : a+=((uint32_t)k[1])<<8; + case 1 : a+=k[0]; + break; + case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ + } + } + + final(a,b,c); + *pc=c; *pb=b; +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/util/lp-io.c b/src/util/lp-io.c new file mode 100644 index 0000000000000000000000000000000000000000..9f46ae3515b30e135310556b7f5e154cef682923 --- /dev/null +++ b/src/util/lp-io.c @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include +#include +#include + +#include "codes/lp-io.h" + +struct io_buffer +{ + tw_lpid gid; + int size; + void* buffer; + struct io_buffer *next; +}; + +struct identifier +{ + char identifier[64]; + struct io_buffer *buffers; + int buffers_count; + int buffers_total_size; + struct identifier *next; +}; + +/* local list of identifiers */ +static struct identifier* identifiers = NULL; +int identifiers_count = 0; + +/* array of all identifiers used across all procs */ +struct identifier global_identifiers[64]; +int global_identifiers_count = 0; + +static int write_id(char* directory, char* identifier, MPI_Comm comm); + +int lp_io_write(tw_lpid gid, char* identifier, int size, void* buffer) +{ + struct identifier* id; + struct io_buffer *buf; + + if(strlen(identifier) >= 64) + { + fprintf(stderr, "Error: identifier %s too big.\n", identifier); + return(-1); + } + + buf = (struct io_buffer*)malloc(sizeof(*buf)); + if(!buf) + return(-1); + + buf->gid = gid; + buf->size = size; + /* allocate copy of data being written */ + buf->buffer = malloc(size); + if(!buf->buffer) + { + free(buf); + return(-1); + } + memcpy(buf->buffer, buffer, size); + buf->next = NULL; + + /* see if we have this identifier already */ + id = identifiers; + while(id && (strcmp(identifier, id->identifier) != 0)) + id = id->next; + + if(id) + { + /* add buffer to front of list */ + buf->next = id->buffers; + id->buffers = buf; + id->buffers_count++; + id->buffers_total_size += size; + } + else + { + /* new identifier */ + id = (struct identifier*)malloc(sizeof(*id)); + if(!id) + { + free(buf->buffer); + free(buf); + return(-1); + } + strcpy(id->identifier, identifier); + id->next = identifiers; + identifiers = id; + id->buffers = buf; + id->buffers_count = 1; + id->buffers_total_size = size; + buf->next = NULL; + identifiers_count++; + } + + return(0); +} + +int lp_io_write_rev(tw_lpid gid, char* identifier){ + struct identifier* id, *id_prev; + struct io_buffer *buf, *buf_prev; + + /* find given identifier */ + if(strlen(identifier) >= 32) + { + fprintf(stderr, "Error: identifier %s too big.\n", identifier); + return(-1); + } + id = identifiers; + while (id && (strcmp(identifier, id->identifier) != 0)){ + id_prev = id; + id = id->next; + } + if (!id){ + fprintf(stderr, "Error: identifier %s not found on reverse for LP %lu.", + identifier,gid); + return(-1); + } + + /* attempt to find previous LP's write. This is made easier by the fact + * that the list is stored newest-to-oldest */ + buf = id->buffers; + buf_prev = NULL; + while (buf){ + if (buf->gid == gid){ break; } + buf_prev = buf; + buf = buf->next; + } + if (!buf){ + fprintf(stderr, "Error: no lp-io write buffer found for LP %lu (reverse write)\n", gid); + return(-1); + } + + id->buffers_count--; + id->buffers_total_size -= buf->size; + if (id->buffers_count == 0){ + /* seg faults caused with empty identifiers for some reason - remove + * this ID */ + if (id == identifiers){ + identifiers = id->next; + } + else{ + id_prev->next = id->next; + } + free(id); + identifiers_count--; + } + /* remove the buffer from the list + * (NULLs for end-of-list are preserved) */ + else if (buf == id->buffers) { /* buf is head of list */ + id->buffers = buf->next; + } + else { /* buf is in list, has a previous element */ + buf_prev->next = buf->next; + } + free(buf->buffer); + free(buf); + return(0); +} + +int lp_io_prepare(char *directory, int flags, lp_io_handle* handle, MPI_Comm comm) +{ + int ret; + int rank; + int save_err; + + MPI_Comm_rank(comm, &rank); + + if(flags & LP_IO_UNIQ_SUFFIX) + { + *handle = (lp_io_handle)malloc(256); + if(!(*handle)) + { + return(-1); + } + if(rank == 0) + sprintf(*handle, "%s-%ld-%ld", directory, (long)getpid(), (long)time(NULL)); + MPI_Bcast(*handle, 256, MPI_CHAR, 0, comm); + } + else + { + *handle = strdup(directory); + if(!(*handle)) + { + return(-1); + } + } + + if(rank == 0) + { + /* create output directory */ + ret = mkdir(*handle, 0775); + if(ret != 0) + { + save_err = errno; + + fprintf(stderr, "mkdir(\"%s\") failed: %s\n", *handle, strerror(save_err)); + return(-1); + } + } + + MPI_Barrier(comm); + + return(0); +} + +int lp_io_flush(lp_io_handle handle, MPI_Comm comm) +{ + int comm_size; + int rank; + MPI_Status status; + int ret; + int i; + struct identifier *id; + int match = 0; + + char* directory = handle; + + memset(global_identifiers, 0, 64*sizeof(global_identifiers[0])); + + MPI_Comm_size(comm, &comm_size); + MPI_Comm_rank(comm, &rank); + + /* The first thing we need to do is come up with a global list of + * identifiers. We can't really guarantee that every MPI proc had data + * written to every identifier, but we want to collectively write each + * ID. + */ + + /* To do this, each rank will receive an initial set of ideas from + * rank+1 and add its own identifiers to the set before transmitting to + * rank-1. Rank 0 will then broadcast the results to everyone. + */ + + /* get array so far from rank +1 */ + if(rank != comm_size-1) + { + ret = MPI_Recv(&global_identifiers_count, 1, MPI_INT, rank+1, 0, comm, &status); + assert(ret == 0); + ret = MPI_Recv(global_identifiers, 64*sizeof(global_identifiers[0]), MPI_BYTE, + rank+1, 0, comm, &status); + assert(ret == 0); + } + + /* add our own entries to the array */ + id = identifiers; + while(id) + { + match = 0; + for(i = 0; iidentifier, global_identifiers[i].identifier) == 0) + { + match = 1; + break; + } + } + if(!match) + { + assert(global_identifiers_count < 64); + global_identifiers[global_identifiers_count] = *id; + global_identifiers_count++; + } + + id = id->next; + } + + /* send results to rank-1 */ + if(rank != 0) + { + ret = MPI_Send(&global_identifiers_count, 1, MPI_INT, rank-1, 0, comm); + assert(ret == 0); + ret = MPI_Send(global_identifiers, 64*sizeof(global_identifiers[0]), MPI_BYTE, + rank-1, 0, comm); + assert(ret == 0); + + } + + /* broadcast results to everyone */ + ret = MPI_Bcast(&global_identifiers_count, 1, MPI_INT, 0, comm); + assert(ret == 0); + ret = MPI_Bcast(global_identifiers, 64*sizeof(global_identifiers[0]), MPI_BYTE, 0, comm); + assert(ret == 0); + + if(rank == 0) + { + printf("LP-IO: writing output to %s/\n", directory); + printf("LP-IO: data files:\n"); + } + + for(i=0; iidentifier) != 0)) + id = id->next; + + /* find my offset */ + if(id) + my_size = id->buffers_total_size; + MPI_Scan(&my_size, &my_offset, 1, MPI_LONG, MPI_SUM, comm); + my_offset -= my_size; + + /* build datatype for our buffers */ + if(id) + { + lengths = (int*)malloc(id->buffers_count*sizeof(int)); + assert(lengths); + displacements = (MPI_Aint*)malloc(id->buffers_count*sizeof(MPI_Aint)); + assert(displacements); + + /* NOTE: some versions of MPI-IO have a bug related to using + * MPI_BOTTOM with hindexed types. We therefore use first pointer as + * base and adjust the others accordingly. + */ + buf = id->buffers; + base = (MPI_Aint)buf->buffer; + /* NOTE: filling in datatype arrays backwards to get buffers in the + * order they were added on each process + */ + i = id->buffers_count-1; + while(buf) + { + displacements[i] = (MPI_Aint)buf->buffer - (MPI_Aint)base; + lengths[i] = buf->size; + i--; + buf = buf->next; + } + MPI_Type_hindexed(id->buffers_count, lengths, displacements, + MPI_BYTE, &mtype); + MPI_Type_commit(&mtype); + free(lengths); + free(displacements); + + ret = MPI_File_write_at_all(fh, my_offset, id->buffers->buffer, 1, mtype, &status); + + MPI_Type_free(&mtype); + } + else + { + /* nothing to write, but participate in collective anyway */ + ret = MPI_File_write_at_all(fh, my_offset, NULL, 0, MPI_BYTE, &status); + } + if(ret != 0) + { + fprintf(stderr, "Error: MPI_File_write_at(%s) failure.\n", file); + return(-1); + } + + ret = MPI_File_close(&fh); + if(ret != 0) + { + fprintf(stderr, "Error: MPI_File_close(%s) failure.\n", file); + return(-1); + } + + return(0); +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ft=c ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/util/lp-msg.c b/src/util/lp-msg.c new file mode 100644 index 0000000000000000000000000000000000000000..b41161001f228fbcec8784aaede17b9cf0c222e3 --- /dev/null +++ b/src/util/lp-msg.c @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2014 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * +*/ + +#include "codes/lp-msg.h" +#include "ross.h" + +void msg_set_header(int magic, int event_type, tw_lpid src, msg_header *h){ + h->magic = magic; + h->event_type = event_type; + h->src = src; +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/util/lp-type-lookup.c b/src/util/lp-type-lookup.c new file mode 100644 index 0000000000000000000000000000000000000000..fe17ee5b9d92e1a94b66944edfe6d117144a7d31 --- /dev/null +++ b/src/util/lp-type-lookup.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2013 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * + */ + +#include +#include + +#include "ross.h" +#include "codes/lp-type-lookup.h" + +#define MAX_LP_TYPES 64 + +struct lp_name_mapping +{ + const char* name; + const tw_lptype* type; +}; + +static struct lp_name_mapping map_array[MAX_LP_TYPES]; +static int map_array_size = 0; + +void lp_type_register(const char* name, const tw_lptype* type) +{ + map_array[map_array_size].name = strdup(name); + assert(map_array[map_array_size].name); + map_array[map_array_size].type = type; + map_array_size++; + + return; +} + +const tw_lptype* lp_type_lookup(const char* name) +{ + int i; + + for(i=0; i +#include +#include "codes/rc-stack.h" +#include "codes/quicklist.h" + +enum rc_stack_mode { + RC_NONOPT, // not in optimistic mode + RC_OPT, // optimistic mode + RC_OPT_DBG // optimistic *debug* mode (requires special handling) +}; + +typedef struct rc_entry_s { + tw_stime time; + void * data; + void (*free_fn)(void*); + struct qlist_head ql; +} rc_entry; + +struct rc_stack { + int count; + enum rc_stack_mode mode; + struct qlist_head head; +}; + +void rc_stack_create(struct rc_stack **s){ + struct rc_stack *ss = (struct rc_stack*)malloc(sizeof(*ss)); + if (ss) { + INIT_QLIST_HEAD(&ss->head); + ss->count = 0; + } + switch (g_tw_synchronization_protocol) { + case OPTIMISTIC: + ss->mode = RC_OPT; + break; + case OPTIMISTIC_DEBUG: + ss->mode = RC_OPT_DBG; + break; + default: + ss->mode = RC_NONOPT; + } + *s = ss; +} + +void rc_stack_destroy(struct rc_stack *s) { + rc_stack_gc(NULL, s); + free(s); +} + +void rc_stack_push( + tw_lp const *lp, + void * data, + void (*free_fn)(void*), + struct rc_stack *s){ + if (s->mode != RC_NONOPT || free_fn == NULL) { + rc_entry * ent = (rc_entry*)malloc(sizeof(*ent)); + assert(ent); + ent->time = tw_now(lp); + ent->data = data; + ent->free_fn = free_fn; + qlist_add_tail(&ent->ql, &s->head); + s->count++; + } + else + free_fn(data); +} + +void* rc_stack_pop(struct rc_stack *s){ + void * ret = NULL; + rc_entry *ent = NULL; + struct qlist_head *item = qlist_pop_back(&s->head); + if (item == NULL) + tw_error(TW_LOC, + "could not pop item from rc stack (stack likely empty)\n"); + s->count--; + ent = qlist_entry(item, rc_entry, ql); + ret = ent->data; + free(ent); + return ret; +} + +int rc_stack_count(struct rc_stack const *s) { return s->count; } + +void rc_stack_gc(tw_lp const *lp, struct rc_stack *s) { + // in optimistic debug mode, we can't gc anything, because we'll be rolling + // back to the beginning + if (s->mode == RC_OPT_DBG) + return; + + struct qlist_head *ent = s->head.next; + while (ent != &s->head) { + rc_entry *r = qlist_entry(ent, rc_entry, ql); + if (lp == NULL || r->time < lp->pe->GVT){ + qlist_del(ent); + if (r->free_fn) r->free_fn(r->data); + free(r); + s->count--; + ent = s->head.next; + } + else + break; + } +} + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + * + * vim: ts=8 sts=4 sw=4 expandtab + */ diff --git a/src/util/resource-lp.c b/src/util/resource-lp.c new file mode 100644 index 0000000000000000000000000000000000000000..33800f7f5c5e8ca515a27dd373701fc90f74e4a5 --- /dev/null +++ b/src/util/resource-lp.c @@ -0,0 +1,591 @@ +/* + * Copyright (C) 2014 University of Chicago. + * See COPYRIGHT notice in top-level directory. + * +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/**** BEGIN SIMULATION DATA STRUCTURES ****/ + +static int resource_magic; /* use this as sanity check on events */ + +/* configuration globals (will be consumed by LP when they init) */ +static uint64_t avail_unanno; +static uint64_t *avail_per_anno; +static const config_anno_map_t *anno_map; + +typedef struct resource_state resource_state; +typedef struct resource_msg resource_msg; +typedef struct pending_op pending_op; + +#define TOKEN_DUMMY ((resource_token_t)-1) + +/* event types */ +enum resource_event +{ + RESOURCE_GET = 100, + RESOURCE_FREE, + RESOURCE_DEQ, + RESOURCE_RESERVE, +}; + +struct resource_state { + resource r; + /* pending operations - if OOM and we are using the 'blocking' method, + * then need to stash parameters. + * Index 0 is the general pool, index 1.. are the reservation-specific + * pools. We take advantage of resource_token_t's status as a simple + * array index to do the proper indexing */ + struct qlist_head pending[MAX_RESERVE+1]; +}; + +/* following struct exists because we want to basically cache a message within + * a message for rc (ewww) */ +struct resource_msg_internal{ + msg_header h; + /* request data */ + uint64_t req; + resource_token_t tok; /* only for reserved calls */ + /* behavior when sending response to caller + * 0 - send the callback immediately if resource unavailable. + * 1 - send the callback when memory is available (danger - deadlock + * possible) */ + int block_on_unavail; + /* callback data */ + struct codes_cb_params cb; +}; + +struct resource_msg { + struct resource_msg_internal i, i_rc; + // for RC (asides from the message itself): the previous minimum resource + // value + uint64_t min_avail_rc; +}; + +struct pending_op { + struct resource_msg_internal m; + struct qlist_head ql; +}; + +/**** END SIMULATION DATA STRUCTURES ****/ + +/**** BEGIN LP, EVENT PROCESSING FUNCTION DECLS ****/ + +/* ROSS LP processing functions */ +static void resource_lp_ind_init( + resource_state * ns, + tw_lp * lp); +static void resource_event_handler( + resource_state * ns, + tw_bf * b, + resource_msg * m, + tw_lp * lp); +static void resource_rev_handler( + resource_state * ns, + tw_bf * b, + resource_msg * m, + tw_lp * lp); +static void resource_finalize( + resource_state * ns, + tw_lp * lp); + +/* ROSS function pointer table for this LP */ +static tw_lptype resource_lp = { + (init_f) resource_lp_ind_init, + (pre_run_f) NULL, + (event_f) resource_event_handler, + (revent_f) resource_rev_handler, + (final_f) resource_finalize, + (map_f) codes_mapping, + sizeof(resource_state), +}; + +/**** END LP, EVENT PROCESSING FUNCTION DECLS ****/ + +/**** BEGIN IMPLEMENTATIONS ****/ + +void resource_lp_ind_init( + resource_state * ns, + tw_lp * lp){ + // get my annotation + const char * anno = codes_mapping_get_annotation_by_lpid(lp->gid); + if (anno == NULL){ + resource_init(avail_unanno, &ns->r); + } + else{ + int idx = configuration_get_annotation_index(anno, anno_map); + if (idx < 0){ + tw_error("resource LP %lu: unable to find annotation " + "%s in configuration\n", lp->gid, anno); + } + else{ + resource_init(avail_per_anno[idx], &ns->r); + } + } + int i; + for (i = 0; i < MAX_RESERVE+1; i++){ + INIT_QLIST_HEAD(&ns->pending[i]); + } +} + +static void resource_response( + struct codes_cb_params const * p, + tw_lp *lp, + int ret, + resource_token_t tok) +{ + SANITY_CHECK_CB(&p->info, resource_return); + + tw_event *e = tw_event_new(p->h.src, codes_local_latency(lp), lp); + void * m = tw_event_data(e); + + GET_INIT_CB_PTRS(p, m, lp->gid, h, tag, rc, resource_return); + + rc->ret = ret; + rc->tok = tok; + + tw_event_send(e); +} + +static void resource_response_rc(tw_lp *lp){ + codes_local_latency_reverse(lp); +} + +/* bitfield usage: + * c0 - enqueued a message + * c1 - sent an ack + * c2 - successfully got the resource */ +static void handle_resource_get( + resource_state * ns, + tw_bf * b, + resource_msg * m, + tw_lp * lp){ + int ret = 1; + int send_ack = 1; + // save the previous minimum for RC + assert(!resource_get_min_avail(m->i.tok, &m->min_avail_rc, &ns->r)); + if (!qlist_empty(&ns->pending[m->i.tok]) || + (ret = resource_get(m->i.req, m->i.tok, &ns->r))){ + /* failed to receive data */ + if (ret == 2) + tw_error(TW_LOC, + "resource LP %lu: invalid token %d passed in " + "(%d tokens created)\n", + lp->gid, m->i.tok, ns->r.num_tokens); + else if (ret == -1) + tw_error(TW_LOC, + "resource LP %lu: unsatisfiable request: " + "token %d, size %lu\n", + lp->gid, m->i.tok, m->i.req); + + if (m->i.block_on_unavail){ + /* queue up operation, save til later */ + b->c0 = 1; + pending_op *op = (pending_op*)malloc(sizeof(pending_op)); + op->m = m->i; /* no need to set rc msg here */ + qlist_add_tail(&op->ql, &ns->pending[m->i.tok]); + send_ack = 0; + } + } + if (send_ack){ + b->c1 = 1; + resource_response(&m->i.cb, lp, ret, TOKEN_DUMMY); + } + + b->c2 = !ret; +} + +/* bitfield usage: + * c0 - enqueued a message + * c1 - sent an ack + * c2 - successfully got the resource */ +static void handle_resource_get_rc( + resource_state * ns, + tw_bf * b, + resource_msg * m, + tw_lp * lp){ + if (b->c0){ + assert(!qlist_empty(&ns->pending[m->i.tok])); + struct qlist_head *ql = qlist_pop_back(&ns->pending[m->i.tok]); + free(qlist_entry(ql, pending_op, ql)); + } + else if (b->c1){ + resource_response_rc(lp); + } + + if (b->c2){ + assert(!resource_restore_min_avail(m->i.tok, m->min_avail_rc, &ns->r)); + assert(!resource_free(m->i.req, m->i.tok, &ns->r)); + } +} + +static void handle_resource_free( + resource_state * ns, + tw_bf * b, + resource_msg * m, + tw_lp * lp){ + assert(!resource_free(m->i.req, m->i.tok, &ns->r)); + /* create an event to pop the next queue item */ + tw_event *e = codes_event_new(lp->gid, codes_local_latency(lp), lp); + resource_msg *m_deq = (resource_msg*)tw_event_data(e); + msg_set_header(resource_magic, RESOURCE_DEQ, lp->gid, &m_deq->i.h); + m_deq->i.tok = m->i.tok; /* only tok is needed, all others grabbed from q */ + tw_event_send(e); +} +static void handle_resource_free_rc( + resource_state * ns, + tw_bf * b, + resource_msg * m, + tw_lp * lp){ + assert(!resource_get(m->i.req, m->i.tok, &ns->r)); + codes_local_latency_reverse(lp); +} + +/* bitfield usage: + * c0 - queue was empty to begin with + * c1 - assuming !c0, alloc succeeded */ +static void handle_resource_deq( + resource_state * ns, + tw_bf * b, + resource_msg * m, + tw_lp * lp){ + if (qlist_empty(&ns->pending[m->i.tok])){ + /* nothing to do */ + b->c0 = 1; + return; + } + + struct qlist_head *front = ns->pending[m->i.tok].next; + pending_op *p = qlist_entry(front, pending_op, ql); + assert(!resource_get_min_avail(m->i.tok, &m->min_avail_rc, &ns->r)); + int ret = resource_get(p->m.req, p->m.tok, &ns->r); + assert(ret != 2 && ret != -1); + if (!ret){ + b->c1 = 1; + /* success, dequeue (saving as rc) and send to client */ + qlist_del(front); + m->i_rc = p->m; + resource_response(&p->m.cb, lp, ret, TOKEN_DUMMY); + free(p); + /* additionally attempt to dequeue next one down */ + tw_event *e = codes_event_new(lp->gid, codes_local_latency(lp), lp); + resource_msg *m_deq = (resource_msg*)tw_event_data(e); + msg_set_header(resource_magic, RESOURCE_DEQ, lp->gid, &m_deq->i.h); + /* only tok is needed, all others grabbed from q */ + m_deq->i.tok = m->i.tok; + tw_event_send(e); + } + /* else do nothing */ +} + +/* bitfield usage: + * c0 - dequeue+alloc success */ +static void handle_resource_deq_rc( + resource_state * ns, + tw_bf * b, + resource_msg * m, + tw_lp * lp){ + if (b->c0){ + return; + } + + if (b->c1){ + /* add operation back to the front of the queue */ + pending_op *op = (pending_op*)malloc(sizeof(pending_op)); + op->m = m->i_rc; + qlist_add(&op->ql, &ns->pending[m->i.tok]); + resource_response_rc(lp); + assert(!resource_restore_min_avail(m->i.tok, m->min_avail_rc, &ns->r)); + assert(!resource_free(op->m.req, op->m.tok, &ns->r)); + /* reverse "deq next" op */ + codes_local_latency_reverse(lp); + } +} + +static void handle_resource_reserve( + resource_state * ns, + tw_bf * b, + resource_msg * m, + tw_lp * lp){ + resource_token_t tok; + int ret = resource_reserve(m->i.req, &tok, &ns->r); + assert(!ret); + resource_response(&m->i.cb, lp, ret, tok); +} +static void handle_resource_reserve_rc( + resource_state * ns, + tw_bf * b, + resource_msg * m, + tw_lp * lp){ + /* this reversal method is essentially a hack that relies on each + * sequential reserve appending to the end of the list + * - we expect reserves to happen strictly at the beginning of the + * simulation */ + /* NOTE: this logic will change if the resource_reserve logic changes */ + ns->r.num_tokens--; + ns->r.max[0] += m->i.req; + ns->r.avail[0] += m->i.req; + + resource_response_rc(lp); +} + +void resource_event_handler( + resource_state * ns, + tw_bf * b, + resource_msg * m, + tw_lp * lp){ + assert(m->i.h.magic == resource_magic); + switch(m->i.h.event_type){ + case RESOURCE_GET: + handle_resource_get(ns,b,m,lp); + break; + case RESOURCE_FREE: + handle_resource_free(ns,b,m,lp); + break; + case RESOURCE_DEQ: + handle_resource_deq(ns,b,m,lp); + break; + case RESOURCE_RESERVE: + handle_resource_reserve(ns,b,m,lp); + break; + default: + assert(0); + } +} +void resource_rev_handler( + resource_state * ns, + tw_bf * b, + resource_msg * m, + tw_lp * lp){ + assert(m->i.h.magic == resource_magic); + switch(m->i.h.event_type){ + case RESOURCE_GET: + handle_resource_get_rc(ns,b,m,lp); + break; + case RESOURCE_FREE: + handle_resource_free_rc(ns,b,m,lp); + break; + case RESOURCE_DEQ: + handle_resource_deq_rc(ns,b,m,lp); + break; + case RESOURCE_RESERVE: + handle_resource_reserve_rc(ns,b,m,lp); + break; + default: + assert(0); + } +} + +void resource_finalize( + resource_state * ns, + tw_lp * lp){ + struct qlist_head *ent; + for (int i = 0; i < MAX_RESERVE+1; i++){ + qlist_for_each(ent, &ns->pending[i]){ + fprintf(stderr, "WARNING: resource LP %lu has a pending allocation\n", + lp->gid); + } + } + + char *out_buf = (char*)malloc(1<<12); + int written; + // see if I'm the "first" resource (currently doing it globally) + if (codes_mapping_get_lp_relative_id(lp->gid, 0, 0) == 0){ + written = sprintf(out_buf, + "# format: \n"); + lp_io_write(lp->gid, RESOURCE_LP_NM, written, out_buf); + } + written = sprintf(out_buf, "%lu", lp->gid); + + // compute peak resource usage + // TODO: wrap this up in the resource interface + for (int i = 0; i < ns->r.num_tokens+1; i++){ + written += sprintf(out_buf+written, " %lu", ns->r.max[i]-ns->r.min_avail[i]); + } + written += sprintf(out_buf+written, "\n"); + lp_io_write(lp->gid, RESOURCE_LP_NM, written, out_buf); +} + +/**** END IMPLEMENTATIONS ****/ + +/**** BEGIN USER-FACING FUNCTIONS ****/ +void resource_lp_init(){ + uint32_t h1=0, h2=0; + + bj_hashlittle2(RESOURCE_LP_NM, strlen(RESOURCE_LP_NM), &h1, &h2); + resource_magic = h1+h2; + + lp_type_register(RESOURCE_LP_NM, &resource_lp); +} + +void resource_lp_configure(){ + + anno_map = codes_mapping_get_lp_anno_map(RESOURCE_LP_NM); + avail_per_anno = (anno_map->num_annos > 0) ? + (uint64_t*)malloc(anno_map->num_annos * sizeof(*avail_per_anno)) : + NULL; + // get the unannotated version + long int avail; + int ret; + if (anno_map->has_unanno_lp > 0){ + ret = configuration_get_value_longint(&config, RESOURCE_LP_NM, + "available", NULL, &avail); + if (ret){ + fprintf(stderr, + "Could not find section:resource value:available for " + "resource LP\n"); + exit(1); + } + assert(avail > 0); + avail_unanno = (uint64_t)avail; + } + for (uint64_t i = 0; i < anno_map->num_annos; i++){ + ret = configuration_get_value_longint(&config, RESOURCE_LP_NM, + "available", anno_map->annotations[i].ptr, &avail); + if (ret){ + fprintf(stderr, + "Could not find section:resource value:available@%s for " + "resource LP\n", anno_map->annotations[i].ptr); + exit(1); + } + assert(avail > 0); + avail_per_anno[i] = (uint64_t)avail; + } +} + +static void resource_lp_issue_event_base( + enum resource_event type, + uint64_t req, + resource_token_t tok, /* only used in reserve_get/free */ + int block_on_unavail, + tw_lp *sender, + struct codes_mctx const * map_ctx, +